When it comes to packaging and delivering applications, legions of organizations are adopting Docker, especially for cloud-based applications. With benefits like caching a cluster of containers, scalability, quick deployment with any dependencies, and scalability, Docker has become the primary preference of many organizations. However, these benefits can be utilized when the best practices are implemented. With that in mind, this article elaborates on all the docker best practices that will help get the best results (from Docker); be it enhancing its security or effectiveness.
Docker is a widely used platform that helps develop and run applications quickly. Moreover, it helps in managing the infrastructure akin to managing the applications. It helps deliver applications quickly by allowing the user to separate them from the infrastructure. Docker's testing and deploying methodologies can help diminish the overall delay between code writing and production running.
Now that a brief about Docker is mentioned, it is time to dig deeper into the primary focus: Docker Best Practices
Docker Best Practices are segregated into different categories depending on their functionality.
#1: Docker Image Building Best Practices:-
Version Docker Images:A common practice among Docker users is using the latest tag for images which is also the default tag for images. Using this tag will eradicate the possibility of identifying the running version code based on the image tag. Not only does it become easier to overwrite it, but it also leads to extreme complications while doing rollbacks. Make sure to avoid using the latest tag, especially for base images, as it could unintentionally lead to the deployment of a new version. Rather than using the default tag, the best practice is to use descriptors like semantic version, timestamps, or Docker image IDs as a tag. With the practice of having a relevant tagging scheme, it becomes easier to tie the tag to the code.
Avoid Storing Secrets in Images: Undeniably, confidential data or secrets like SSH keys, passwords, and TLS certificates are highly sensitive for an organization. Storing such data in images without encryption can make it easier for anyone to extract and exploit it. This situation is extremely common when images are pushed into a public registry. Rather than that, injecting these through build-time arguments, environment variables, and an orchestration tool is the best practice. In addition, sensitive data can also be added to the .dockerignore file. Another practice to accomplish this goal is by being specific about the files that should be copied over the image. Environment Variables: Environment variables are primarily used to keep the application flexible and secure. These can also be used to pass on sensitive information or secrets. However, these will still be visible in the logs, child processes, linked containers, and docker inspect. The following is a frequently used approach for managing secrets.
$ docker run --detach --env "DATABASE_PASSWORD=SuperSecretSauce" python:3.9-slim
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/c20b0cfd643cd4a19246ccf204e2997af70f6b21/public/get-pip.pyPYTHON_GET_PIP_SHA256=fa6f3fb93cce234cd4e8dd2beb54a51ab9c247653b52855a48dd44e6b21ff28b If the motive is to keep the secrets slightly secure, this is the way. However, it does not offer the utmost security. In case the secrets are to be shared in a shared volume, the best practice is to encrypt the secrets.
Using a .dockerignore File: The .dockerignore file is used to define the required build context. Before an image is built, the user has to specify the files and folders that should be excluded from the initial build context sent to the Docker daemon which is done with the help of the .dockerignore file.
Prior to evaluating the COPY or ADD commands, the entire project's root is sent to the Docker daemon, making it a hefty deal. Apart from that, there can be stances when the daemon and the Docker CLI are on different machines. In that case, the .dockerignore file should be added to local secrets, temporary files, local development files, or build logs. Doing so can boost the build process, avoid secret leaks, and reduce the Docker image size.
Image Linting and Scanning: Inspecting the source code for any stylistic or programmatic error that can cause issues is called lining. Linting can help ensure that the Dockerfiles comply with the right practice and can be maintained. This process can also be followed in images to determine any underlying vulnerabilities or issues.
Signing and Verifying Images: Sometimes, tampering can be done by man-in-the-middle attacks on the images used to run the production code. By using Docker Content Trust, you can sign and verify the images, allowing you to determine whether the Docker images have been tampered with. All you have to do is set up the DOCKER_CONTENT_TRUST=1 environment variable.
If an image is pulled and has not been signed, the following error will pop up.
Error: remote trust data does not exist for docker.io/namespace/unsigned-image:
notary.docker.io does not have trust data for docker.io/namespace/unsigned-image
#2: Dockerfiles Best Practices:
Multi-Stage Builds: Dockerfiles can be divided into numerous stages through Multi-stage builds. With this break-up, the final stage is when the image is created so the tool and dependencies of application building can be discarded. In addition, multi-stage builds will lead to a modular, lean, lighter, and secure image, saving time and money.
Appropriate Docker File Command Order: The Dockerfile commands play a crucial role in its efficiency. To enhance the builds, Docker caches every layer in a specific Dockerfile. Whenever there is a change in a step, the entire cache will become invalid for all the steps afterward.
This practice is highly inefficient in a Docker container.Instead of putting files randomly, the right practice is to put the frequently changed files at the end of the Dockerfile.
Apart from that, you can also put layers with a higher possibility of changes lower in the Dockerfile, and turn off caching in a Docker build whenever necessary by adding --no-cache=True flag.
Small Docker Base Images: When it comes to pushing, pulling, and building images, the industry-wide practice is to ensure that the images are as small as possible. This practice is because small images can make the process quicker and safer and ensure that only the libraries and dependencies included are essential for running the application.
Regarding picking the right size, here is a quick comparison of different Docker base images for Python.
REPOSITORY
TAG
SIZE
Python
3.9.6-alpine3.14
45.1MB
Python
3.9.6-slim
115MB
Python
3.9.6-slim-buster
115MB
Python
3.9.6
886MB
Python
3.9.6-buster
886MB
It is all about finding the right balance, allowing you to have small Docker base images.
Reduce the Number of Layers: With every layer, the size of the image increases due to caching. As stated above, keeping the image size minimal is the right practice. However, increasing the number of layers may not get the job done.
The number of layers can be reduced by combining related commands whenever possible. Apart from that, eradicating unwanted files in the RUN step and minimizing running apt-get upgrade can also help in this task.
However, this reduction in layer numbers should not be forced as it can lead to unnecessary issues. It should be done only whenever it is possible rather than making it possible forcefully.
Use COPY Instead of ADD: Numerous users believe that both COPY and ADD commands serve the same purpose with the same nature. Even though they are used to copy files from a location to a Docker image, they have certain differences. COPY is used to copy local files from the Docker host to the image. However, ADD can accomplish the same task but can also download external files and unpack the contents of any compressed file in the desired location. With a massive difference between the two, the preferred command should be COPY instead of ADD. However, you can use ADD if you want the additional functionality of ADD.
Use One Container for One Process: Even though an application stack can run multiple processes in a single container, it is always advised to run only one process per container. This practice is considered one of the best for Dockerfile because it makes the below-mentioned services easier.
Reusability: When another service requires a containerized database, the same database container can be used.
Portability: As there are fewer processes to work on, making security patches becomes easier.
Scalability: Services can be scaled horizontally to manage traffic when there is a specific container.
HEALTHCHECK Inclusion: An APU in Docker can provide a deeper insight into the status of the running process in the container. Not just running status, but stuck, still launching, and working status can be attained in Docker.
However, the HEALTHCHECK instruction can be used to interact with the API even further. You can also set custom endpoints and configure the instruction to test the data.
You can monitor the health status by the following docker inspect:docker inspect —format '{{json .State.Health }}' ab94f2ac7889{ 'Status': 'healthy', 'FailingStreak': 0, 'Log': [
{
'Start': '2021-09-28T15:22:57.5764644Z',
'End': '2021-09-28T15:22:57.7825527Z',
'ExitCode': 0,
'Output': '''
#3: Docker Development Best Practices:
CI/CD for Testing and Deployment: Experts recommend using Docker Hub or any other CI/CD pipeline to build and tag a Docker image whenever a pull request is created. Furthermore, the images should be signed by the development, security, and testing teams before they are pushed to production so that it is constantly tested for quality by the desired teams.
Use Different Environments for Development and Testing: One of the best practices while using Docker for development is creating different testing and development environments. Doing so will allow the developer to keep the Docker files isolated and execute them without influencing the final build after testing.
Update Docker to the Latest Version: Before you begin working on a Docker project, you need to ensure that you update the Docker to the latest version. Even though it will not directly impact the project, it will provide you with the latest features that Docker has to offer. New updates also have certain security features, safeguarding the project from potential attacks.
#4: Docker Container Best Practices:
Frequently Backup a Single Manager Node: A common Docker container practice is to back a single managed node frequently, which helps admins in restoration. Docker Swarm and Universal Control Plane data are part of every node, so backing up a single manager node can get the job done for the admins.
Cloud Deployment of a Docker Container: When deploying a Docker container to a cloud, both Amazon Web Services and Microsoft Azure do not have integrated hosts optimized for Docker. They use the Kubernetes cluster for deployment. A standard virtual machine should be created by the admins who prefer to deploy a single container. Apart from that, securing the secure socket shell and installing Docker is the next step. Admins can now deploy the application on a cloud after installing Docker.
Control Docker Containers through a Load Balancer: A load balancer helps admins get good control over Docker containers which helps them in making containers highly available and scalable. The most commonly used load balancer is NGINX which can easily be installed on Docker. This load balancer supports multiple balancing methods, static and dynamic caching, rate limiting, and multiple distinct applications.
#5: Docker Security Best Practices:
APIs and Network Configuration: One of the biggest security threats is an inappropriately configured API which can be the target point of hackers. Make sure to configure the API securely in a way that it does not make containers publicly exposed. Practice like certificate-based authentication is an excellent way to start this task.
Limit Container Capabilities: Docker comes with a default configuration for containers where they can have capabilities that may not be required for them to perform their services. These unnecessary privileges can be a gateway for security breaches. The best practice to avoid such security vulnerabilities is to limit the container capabilities to only those which are required by the container to run applications.
Restrict System Resource Usage: Each container can use infrastructure resources like CPU, memory, and network bandwidth. Limiting the usage for each container ensures that no container uses excessive resources than required so that the services are not disrupted. Moreover, the resources will be used efficiently.
Use Trusted Images: Using images from any source, including untrusted ones, can weaken the Docker container's security. Make sure to get Docker base images from trusted sources only. Also, the images should be configured correctly and signed by enabling the Docker Content Trust.
Least Privileged User: Docker containers come with root privileges by default, providing them admin access to the container and the host. This access can make container security vulnerable and easier for hackers to exploit Docker. Setting a least-privileged user will provide only the required privileges to run containers, ultimately eradicating the aforementioned issue and improving Docker security.
Limit Access to Container Files: Transient container files are accessed frequently as they need constant bug fixes and upgrades which exposes them drastically. This issue can be solved when the container logs are maintained outside the container, as it will minimize the usage of container files. Moreover, the team will not access logs for fixing underlying issues in the container.
#6: Docker Logging Best Practices:
Logging from Application: Logging directly from the application is a method where applications within the container manage the logging through a framework. The developers will have the utmost control over the logging event when using this method. Furthermore, the applications remain independent from containers as well.
Logging Drivers: Logging drivers is a unique feature of Docker that helps read data by the stderr or stdout streams of the container as they are specifically configured to accomplish this task. Once done, the host machine stores log files that include the prior data. Logging drivers are used because they are native to Docker and centralize the log to a single location.
Dedicated Container for Logging: Having a dedicated container for logging helps in eradicating dependencies on host machines. This container will be responsible for log file management within the Docker environment. This dedicated logging container will cumulate logs from other containers and monitor and analyze them automatically. Furthermore, it can forward the log files to a central location. Another excellent thing about this practice is that you can deploy more containers whenever you require.
Sidecar Method: The Sidecar method is undoubtedly among the best if you want to manage microservices architecture. Here, the sidecars run simultaneously with the parent application, where they share the same network and volume. These shared resources allow you to expand the app functionalities and eradicate the need to install any extra configurations.
#7: Docker Compose Best Practices:
Adjust Compose file for Production: Sometimes, making certain changes like binding different ports on the host, enhancing extra services, different setup for environment variables, and eradicating volume bindings are necessary to prepare for production. To accomplish this task, the best practice is to define a new Compose file that will specify the desired configuration. In this configuration file, you are only required to add changes you want from the original Compose file. You can apply the new Compose file over docker-compose.yml for a new configuration. You can guide Compose to use the second configuration file with the —f option.
Deploy Changes: Rebuilding the image and recreating application containers is necessary whenever a change is implemented to an app code. The below-mentioned code can be used to redeploy web service. $ docker-compose build web $ docker-compose up --no-deps -d webWith this code, the web image will be rebuilt and stopped. Afterward, it will destroy and recreate the web service. The inclusion of —no-deps flag avoids the creation of any services by Compose used by the web.
Run Compose on a Single Server: Compose can be used to deploy an application to a remote Docker after setting up DOCKER_CERT_PATH, DOCKER_HOST, and DOCKER_TLS_VERIFY environment variables. After setting up these variables, the docker-compose commands will no longer require any additional configuration and perform as desired.
Docker Services Offered by ThinkSys:
Docker Implementation: ThinkSys Inc. provides an industry-leading Docker implementation service where our professionals will understand the requirements of your organization and create a roadmap for its implementation. Our implementation services include configuration of Docker in your IT infrastructure and integration of Docker with other applications.
Docker Container Management: Our Docker container management services start by analyzing the containers and identifying any underlying issues. Our experts will manage the containers in this service to ensure they perform effectively and efficiently. Furthermore, we will try to optimize the Docker environment while keeping it as secure as possible.
Docker Consulting Service: Whether you want to implement Docker containers or just want to know now about Dockers, our docker experts. can help you with Docker consulting services. With our services, you can upgrade to a microservice-based architecture.
Docker Support: Bugs and issues can occur during or after Docker implementation. Our Docker experts can provide you with around-the-clock Docker support to ensure that your Docker containers remain functional. With our experienced professionals by your side, you are sure to get top-notch Docker support whenever you want.
Docker Customization: Do you want to customize your Docker containers? ThinkSys Inc. can help you personalize your Docker through custom plugins and API. These plugins can be modified as per your organization's needs as well.
Docker Security: Whether you want to enhance the security of your existing Dockerized environment or make sure that your new Docker remains secure, all you have to do is connect with ThinkSys Docker Specialists. We will use the best Docker security practices to ensure that your Docker environment remains highly secure and meets all the desired security standards.
Proof of Concept: Sometimes, you want to accomplish a task in your Docker but remain unsure whether it will be the right decision. ThinkSys Inc. will analyze your Docker containers and the new task you want to complete. Based on that study, you will be provided with a report on how accomplishing this complex task will influence your organization and whether it is worth it or not.
Container Management: ThinkSys Inc. can also assist you in the management of your containers for mobile and web-based applications that use Kubernetes. Depending on your organization's requirements, you will get automatic container scaling, deployment, and creation.
Docker is one of the most widely used software platforms for software building, testing, and deployment. With tons of features, there is also a possibility of additional complexities. The Docker practices mentioned above will not just reduce the complexities in Docker but will ensure that you get the best outcome from this software platform.
Sometimes professional assistance is required for using Docker. With over a decade of experience, ThinkSys can provide the best docker assistance you need. The team at ThinkSys is equipped with the industry-leading tools and practices that will help you get the best outcome from Docker.
FAQ(Docker Best Practices)
Q1: What operating systems does Docker Support?
Docker is compatible with all the major operating systems including Windows, macOS, and Linux with native support for Windows (x86-64) and Linux (x86-64, and other architectures).
Q2: How many processes can a Docker container run?
Though a Docker container can run multiple processes, running a single application in a container is advisable. Horizontal scaling can be made more accessible when the applications are split into multiple containers.
Q3: Can data be stored in Docker images?
Docker allows the user to store data in the images. However, this is not the proper practice as it not can lead to data loss or reduce data security. Instead, it is advised to store data directly on the host.