Docker Implementation


Docker is the most popular technology for implementing containers. It can be found everywhere, from local development machines to production servers. Knowing how to implement Docker containers is now more important than ever. A poorly constructed Docker container is not only a security threat, but also can slow down production servers and the deployment process. In this article, I have discussed several Docker commands you can use to implement your containers in local and production environments.
Using No-Cached Layer
When debugging your application, you want a clean installation. This eliminates any unexpected behaviour raised due to the cached layer. However, for security reasons, you should occasionally create an image without the cached layer. Sometimes, Docker build caches can be corrupted and generate inconsistent results.
For all the above scenarios, you can build a Docker image without using a cache layer.
docker build --no-cache -t dummy:latest .
Running Container with Non-Root User
By default, Docker runs a container with the root user. This directly affects the container security, because anyone who has access to the container has access to the root user. There are two ways to handle this.
Create a non-root user and use it in the Dockerfile
Use
-u
argument in docker run
Option 1: Dockerfile
FROM python:3.11
RUN useradd ritwik -ms /bin/bash ritwik
WORKDIR /app
COPY ./requirements.txt ./
RUN pip install -r requirements.txt
COPY ./src ./src
USER ritwik
ENTRYPOINT ["python"]
CMD ["/app/src/server.py"]
When you run the container, it uses the user ritwik to run the container.
Option 2: -u Argument
FROM alpine
CMD ["whoami"]
docker run -u 1001:1001 testuser
Even if user 1001 does not exist, the container does not use the root user.
Creating Image Tags
Creating tags for your image is very crucial. There are two popular ways of naming your tags.
Use the latest commit hash
Use the release date
Option 1: Commit Hash
docker build -t myserver:$(git rev-parse --short HEAD) .
Option 2: Release Date
Windows Powershell
docker build -t myserver:$(Get-Date -Format "yyyy-MM-dd") .
Linux Bash
docker build -t myserver:$(date +%Y-%m-%d) .
Restart Policy
Docker comes with four restart policies.
no
on failure with max retries
always
unless-stopped
no policy dictates, the container will not restart under any circumstances.
docker run -d --restart no myserver
On-failure policy dictates, the container restarts if the exit code is non-zero. You can also mention the number of retries.
docker run -d --restart on-failure:3 redis
FROM alpine
# Will exit with non-zero code
CMD ["sleep", "1", "&&", "exit", "1"]
always policy dictates, the container will restart without any condition. If manually stopped, the container will restart on Docker daemon restart.
# Mention at container run
docker run -d --restart always redis
# Update existing container policy
docker update --restart always eb223
When Stopped Manually
Once the Docker daemon is restarted, the container starts restarting.
unless-stopped policy dictates, the container does not restart automatically when the Docker daemon is restarted.
docker update --restart unless-stopped eb223
In case you want to apply the same policy on every container, you can run the following command.
docker update --restart unless-stopped $(docker ps -q)
Remove Container Automatically
When trying out different commands or configuring a Dockerfile, you will create the container from the same image. It is a good idea to give the container a name. But Docker does not allow more than one container to have the same name. That is why deleting the previous container is essential. Docker allows you to delete a container when it is stopped automatically using the —rm argument.
# --rm argument makes sure that container is deleted when it is stopped
docker run --rm -d -p 8088:8088 --name server myserver:latest
You cannot use the —rm with the —restart argument.
Container Logs
Logs are a crucial part of any application. Finding the source of error, tracing warnings, and checking the flow of requests are just a few examples of the benefits of Logs.
docker logs server
This command prints all the logs generated by an application
You may want to see live logs to analyse the application in real-time.
docker logs server --follow
Or you can also track the record of the last n logs.
# Last 30 logs
docker logs server --tail 30
When you run your application on a local machine or you are storing the logs in a container instead of a third-party service, restricting the size of logs is crucial. If not restricted, it can stop your system unexpectedly.
# Limit log file size to 10 MB.
docker run --rm -d --log-opt max-size=10m -p 8088:8088 --name server myserver:latest
# Keep up to 3 rotated log files (i.e., 30 MB total).
docker run --rm -d --log-opt max-size=10m --log-opt max-file=3 -p 8088:8088 --name server myserver:latest
Copy Files
Sometimes, you may want to copy a file to/from your container. You can copy a config file to your container without re-creating the image. Or you can copy the logs from your container for analysis or debugging purposes.
docker cp ./config.ini server:/app/config/config.ini
Now you can restart your application and load the new configuration.
docker cp server:/usr/logs/server.log ./server.log
You can analyse the log file or upload it to any service that can analyse the log.
One more interesting use of Docker cp is using a different OS. If you are using Windows and need to generate a file in a Linux environment, so it can be compatible with your servers in the cloud. You can create a Linux container, generate the file, and copy it from the container. Then push the file to your server. One great example is AWS Lambda Layer. You can check this article.
Healthcheck
This is a part of Dockefile configuration. You can check the health of your application or an application on which your app depends. For example, your app depends on a PostgreSQL database. You need to check if the database is on and running.
FROM python:3.11-slim
RUN apt-get update && apt-get install -y \
netcat \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY ./src ./src
# Add healthcheck to ensure PostgreSQL is available
HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
CMD pg_isready -h localhost -p 3600 || exit 1
CMD ["python", "/app/src/server.py"]
Or you can use the curl command.
# Add healthcheck to ensure endpoint returns status code Ok
HEALTHCHECK --interval=10s CMD curl -f http://localhost:5000/health || exit 1
Subscribe to my newsletter
Read articles from Ritwik Math directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Ritwik Math
Ritwik Math
As a seasoned senior web developer with a wealth of experience in Python, Javascript, web development, MySQL, MongoDB, and React, I am passionate about crafting exceptional digital experiences that delight users and drive business success.