Optimizing docker image

Optimizing Docker image and Docker permissions.

Hi, this is second blog of series where we dockerize django application. Here is link to first part if you want to start from beginning it. In this blog we will be optimizing our docker image size and managing docker permissions.

First we will be looking ways of optimizing the size of our docker image. Reducing our docker image size can help us speed up our build process. One of main reason to avoid bigger docker images is they increase potential security vulnerabilities. Some ways to reduce docker image sizes:

  • Using minimal base images.

  • Making multistage builds.

  • Minimizing number of layers.

  • Using Dockerignore.

Using minimal base images.

We can find different images to download from dockerhub. Choosing right docker image is important for optimizing size of your image. One of image with minimal footprint is alpine base image. We have been using alpine in this blog. You can further reduce image size by using distroless images.

Making Multistage builds

First lets check size of our image.

Enter command to see size of image we have created :

docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

djangowithdocker_web latest dfc89fa29239 41 minutes ago 104MB

Here we can see size of our docker image to be 104MB

Now, lets update our dockerfile.

FROM python:3.10-alpine AS builder

ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1

RUN pip install --upgrade pip

ENV APP_DIR /home/DockerWithDjango

WORKDIR ${APP_DIR}

ADD requirements.txt ${APP_DIR}/

RUN pip install -r ${APP_DIR}/requirements.txt

COPY . ${APP_DIR}

FROM python:3.10-alpine

WORKDIR /home
COPY --from=builder /usr/local/lib/python3.10/site-packages/ /usr/local/lib/python3.10/site-packages/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
COPY --from=builder /home/DockerWithDjango/ /home/

EXPOSE 8000

CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

Now build image by running following command and check image size again.

docker-compose build

REPOSITORY                TAG        IMAGE ID         CREATED        SIZE
djangowithdocker_web   latest        ed890f647878   2 minutes ago     92.4MB

New size of our image is 92.4MB. It has decreased from 104MB to 92.4MB. Since our project has very few packages installed so size is small and decreased size is also less. When project size increases multi-stage build will decrease lot of size.

Minimizing number of layers

An image is a read-only template with instructions for creating a Docker container. A Docker image is built up from a series of layers. Each step in Dockerfile creates a new layer. Instructions like RUN, COPY, ADD creates new layer and each layer adds build execution time and increases the storage requirements of the image. The other instructions create intermediate layers and do not influence the size of image. So, while creating Dockerfile we need to be careful about number of layers that is being created as it will affect size of our docker image.

Using Dockerignore

Using .dockerignore file can help us remove unwanted files from build. This file works similar to .gitignore file. We list files that we want docker to ignore during building our docker image.

Lets create a new .dockerignore file and list files we want docker to ignore. This file usually may contain logs, cache folders, git, markdown files etc. Here we will add list to ignore for our django application.

```

pycache/

.git

*.sqlite3

env/

*.md

```

Changing user permission

Running docker as root user may lead to broken permissions. Lets add new user group and create a new user. Then we will manage permission of our project to newly created user. ``` FROM python:3.10-alpine AS builder

ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1

RUN addgroup -S -g 1000 django-with-docker && adduser -S -u 1000 django-with-docker -G django-with-docker

RUN pip install --upgrade pip

ENV APP_DIR /home/DockerWithDjango

WORKDIR ${APP_DIR}

ADD requirements.txt ${APP_DIR}/

RUN pip install -r ${APP_DIR}/requirements.txt

COPY . ${APP_DIR}

FROM python:3.10-alpine

WORKDIR /home COPY --from=builder /usr/local/lib/python3.10/site-packages/ /usr/local/lib/python3.10/site-packages/ COPY --from=builder /usr/local/bin/ /usr/local/bin/ COPY --from=builder /home/DockerWithDjango/ /home/

RUN chown -R 1000:1000 /home USER 1000

EXPOSE 8000 ``` In this blog we optimized our Dockerfile size and manage permissions of our django project inside docker.