Month: September 2019

Help me Understand Containerisation (Docker)

I was looking at nodeJS servers, how they work and ways to scale them. I came across a best practices repo and it said: “Be stateless, kill your Servers almost every day“.

I’ve always been skeptical of docker and containers – granted I haven’t used them extensively but I’ve always thought of them as needless abstractions and added complexity that make the developer’s and system administrator’s lives harder.

The tides have pushed me towards it though…so I asked a friend to Help me understand containerisation.

Help Me Understand Containerisation

Going back to the article I was reading it said: Many successful products treat servers like a phoenix bird – it dies and is reborn periodically without any damage. This allows adding and removing servers dynamically without any side-effects.

Some things to avoid with this phoenix stategy is:

  • Saving uploaded files locally on the server
  • Storing authenticated sessions in local file or memory
  • Storing information in a global object

Q: Do you have to store any type of data (e.g. user sessions, cache, uploaded files) within external data stores?

Q: So the container part is only application code running…no persistance?

A: in general i find it best to keep persistence out of the container. There’s things you can do .. but generally it’s not a great idea

Q: Does it / is it supposed to make your life easier?

A: yeah. I don’t do anything without containers these days

Q: Containers and container management are 2 seperate topics?

A: yeah. I don’t do anything without containers these days

I think the easiest way to think of a container is like an .exe (that packages the operating system and all requirements). So once a container is built, it can run anywhere that containers run.

Q: Except the db and session persistance is external

A: doesn’t have to be .. but it is another moving part

A: the quickest easiest benefit of containers is to use them for dev. (From a python perspective..) e.g.: I don’t use venv anymore, cause everything is in a container

so .. on dev, I have externalized my db, but you don’t really need to do that

Q: Alright but another argument is the scaling one…so when black friday comes you can simply deploy more containers and have them load balanced. but what is doing the load balancing?

A: yeah .. that’s a little more complicated though .. and you’d be looking at k8s for that. (For loadbalancing) Usually that’s k8s (swarm in my case) though .. that’s going to depend a lot on your setup.E.g.: I just have kong replicated with spread (so it goes on every machine in the swarm)

Q: If you are not using a cloud provider and want this on a cluster of vm’s – is that hard or easy?

A: Setting up and managing k8s is not easy. If you want to go this way (which is probably the right answer), I would strongly recommend using a managed solution. DO (DigitalOcean) have a nice managed solution -which is still just VMs at the end of the day.

Q: What is spread?

A: Spread is a replication technique for swarm – so it will spread the app onto a container on every node in the swarm. Swarm is much easier to get your head around – but it’s a dying tech. K8s has def won that battle… but I reckon the first thing you should do is get comfortable with containers for dev.

Q: Everything easy and simple has to die

A: In fairness it’s nowhere near as good as k8s.

Q: ah looks like https://www.okd.io/ would be the thing to use in this case

A: yeah .. there’s a bunch of things out there. Okd looks lower level than I would like to go 😉

Q (Comment): Yip, I mean someone else manage the OKD thing…and I can just use it as if it were a managed service

In my head the docker process would involve the following steps:

  1. Container dev workflow
  2. Container ci workflow
  3. Container deployment
  4. Container scaling

The Container Development Process

A: ok .. you can probably actually setup a blank project and we can get a base django setup up and running if you like?

Steps

Make a Directory and add a Dockerfile in it. What is a Dockerfile? A file containing all the commands (on commandline) to build a docker image.

The docker build command builds an image from a Dockerfile and a context.

More info on building your docker file in the Dockerfile reference

The contents of the Dockerfile should be (There are other Dockerfile examples available caktusgroup, dev.to, testdriven.io


# pull official base image
FROM python:3.7

LABEL maintainer="Name <stephen@example.com>"
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
RUN mkdir -p /code
WORKDIR /code

# Install dependencies
COPY requirements.txt /code/
RUN pip install -U pip
RUN pip install --no-cache-dir -r requirements.txt

# Copy Project
COPY . /code/

EXPOSE 8000

For this to work, we need the requirements.txt to be present. So for now just put in django.

While looking at different DockerFiles I found these best practices for using docker. It seems like the base image is important and people recommend small ones. There is another article commenting that alpine is not the way to go. For now it is not worth wasting time and you don’t need to worry about the different image variants.

PYTHONDONTWRITEBYTECODE: Prevents Python from writing pyc files to disc (equivalent to python -B option)

PYTHONUNBUFFERED: Prevents Python from buffering stdout and stderr (equivalent to python -u option)

Then create a docker-compose.yaml in the same directory. Docker compose is a tool for defining and running mulitple container docker applications. A way to link docker containers together. Compose works in all environments: production, staging, development, testing, as well as CI workflows.

So we have created a docker image for our django application code, but now we need to combine that with a database or just set some other settings. Take a look at the compose file reference.

Add the following:


version: '3.7'

services:
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"

This part:


volumes:
  - .:/code

Maps your current directory on your machine (host) to /code inside the container. You do that in dev – not in production.

Mapping your local volume to a volume in the container means that changes made locally will cause the server to reload on the docker container.

In docker compose remember to list your services in the order you expect them to start.

If you don’t have an existing docker project in your directory then run:

docker-compose run --rm web django-admin.py startproject {projectname} .

You want to get in the habit of initialising projects in the container

Next get it up and running with:

docker-compose up

It then should run in the foreground, the same way a django project runs. You can stop it with ctrl + c.

A note on making changes to the Dockerfile or requirements.txt

docker-build-process

So next time you run docker build it will be faster or even skip some things. However if you add a new dependency to requirements you must manually
docker compose build

It is important to commit your Dockerfile and docker-compose.yaml to git.

docker-change-python-version set-python-docker-imageAdding Postgres

To add a po

The Container CI Workflow

We are going to use gitlab for Continuous Integration. Gitlab is closely aligned with a container based development workflow.

jenkins-analog-player-in-containerised-world

A: I use gitlab for my ci .. so that part will depend on gitlab ..

A: but containers do make that easy .. cause you just need to build the container .. and then you can do everything inside the container

gitlab-ci-containerisation

 

The Container Deployment

Where should you DB and session storage live?

What is teh backup strategy?

Lets do some autoscaling.