{"id":20817197,"url":"https://github.com/kgoksal/docker-best-practices","last_synced_at":"2026-03-16T11:03:16.451Z","repository":{"id":250603106,"uuid":"834919498","full_name":"KGoksal/Docker-Best-Practices","owner":"KGoksal","description":"Dockerfile practices","archived":false,"fork":false,"pushed_at":"2024-09-27T09:33:15.000Z","size":1250,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-18T15:55:19.686Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KGoksal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-28T17:59:11.000Z","updated_at":"2024-09-27T09:33:18.000Z","dependencies_parsed_at":"2025-01-18T15:54:15.148Z","dependency_job_id":"d059b6d4-bbb2-42a5-9d94-5d8574aa597b","html_url":"https://github.com/KGoksal/Docker-Best-Practices","commit_stats":null,"previous_names":["kgoksal/docker-best-practices"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KGoksal%2FDocker-Best-Practices","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KGoksal%2FDocker-Best-Practices/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KGoksal%2FDocker-Best-Practices/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KGoksal%2FDocker-Best-Practices/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KGoksal","download_url":"https://codeload.github.com/KGoksal/Docker-Best-Practices/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243165501,"owners_count":20246722,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T21:39:49.459Z","updated_at":"2025-12-25T11:55:36.850Z","avatar_url":"https://github.com/KGoksal.png","language":"Dockerfile","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Docker Best Practices \n## A. BEST PRACTICE RULES\n### 1. Use an official and verified Docker image as a base image, whenever available.\nInstead of taking a base operating system image (like ubuntu) and installing node.js, npm and whatever other tools you need for your application, **use the official node image for your application.**\n### 2. Use specific Docker image versions\nSo instead of a random latest image tag, you want to fixate the version and just like you deploy your own application with a specific version you want to use the official image with a specific version. \n-  **the more specific the better** Transparency to know exactly what version of the base image you're using\n\n### 3. Use Small-Sized Official Images\nWhen choosing a Node.js image, you will see there are actually multiple official images. Not only with different version numbers, but also with different operating system distributions. So pay attention to these:\n\n-  **1) Image Size**\n  In contrast having **smaller images** means you need **less storage** space in image repository as well as on a deployment server and of course you can transfer the images **faster when pulling or pushing** them from the repository.\n-  **2) Security Issue**\n-  In comparison by using smaller images with leaner OS distributions, which only bundle the necessary system tools and libraries, you're also **minimizing the attack surface and making sure that you build more secure images.**\n-  = So the best practice here would be to select an image with a **specific version based on a leaner OS distribution like alpine** for example: Alpine has everything you need to start your application in a container, but is much more lightweight. And for most of the images that you look on a Docker Hub, you will see a version tag with alpine distribution inside.\n### 4. OPTIMIZE CACHING FOR IMAGE LAYERS WHEN BUILDING AN IMAGE \nWhen you rebuild your image, if your Dockerfile hasn't changed, Docker will just use the cached layers to build the image.\n**Advantages of cached image layers:**\n- ✅ **Faster image building**\n- ✅ **Faster pulling and pushing of new image versions:** Only the newly added layers will be downloaded, the rest are already locally cached by Docker.\n- ✅ **Optimize the Caching**\n- Order your commands in the Dockerfile from the least to the most frequently changing commands to take advantage of caching and this way optimize how fast the image gets built. 🚀\n\n### 5. Use .dockerignore file\nCreate this .dockerignore file and list all the files and folders that we want to be ignored and when building the image, Docker will look at the contents and ignore anything specified inside. It leads to reduce image size We don't need the auto-generated folders, like: \n- targets,\n- build folder,\n- readme file etc.\n\n### 6. Make use of Multi-Stage Builds\nLet's say there are some contents (**like development, testing tools and libraries**) in your project that you need for building the image - so during the\nbuild process - but **you DON'T NEED them in the final image itself to run the application**. If you keep these artifacts in your final image even though they're absolutely unnecessary for running the application, it will again result in an increased image size and increased attack surface. \n- = separate the build stage from the runtime stage.\n\n- The multi-stage builds feature allows you to use **multiple temporary images during the build process**, but **keep only the latest image as the final artifact**:\nSo these previous steps will be discarded.\n_- Separation of Build Tools and Dependencies from what's needed for runtime_\n_- Less dependencies and reduced image size_\n\n\n### 7. USE THE LEAST PRIVILEGED USER \n-\u003e By default, when a Dockerfile does not specify a user, it uses a root user. But in reality there is mostly no reason to run containers with root privileges. This basically introduces a security issue, because when container starts on the host it, will potentially have root access on the Docker host. So running an application inside the container with a root user will make it easier for an attacker to escalate privileges on the host and basically get hold of the underlying host and its processes, not only the container itself. Especially if the application inside the container is vulnerable to exploitation.\n\n- To avoid this, the best practice is to simply create a dedicated user and a dedicated group in the Docker image to run the application and also run the application inside the container with that user:\n- You can use a directive called USER with the username and then start the application conveniently.\n- **Tip:** Some images already have a generic user bundled in, which you can use. So you don't have to create a new one. For example the node.js image already bundles a generic user called node, which you can simply use to run the application inside the container. \n\n### 8. Scan your Images for Security Vulnerabilities\nOnce you build the image to scan it for security vulnerabilities using the **docker scan command**. In the background Docker actually uses a service called snyk to do the vulnerability scanning of the images. The scan uses a database of vulnerabilities, which gets constantly updated. You can see:\n\n    1) the type of vulnerability,\n    \n    2) a URL for more information\n    \n    3) but also what's very useful and interesting you see which version of the relevant library actually fixes that vulnerability. So you can update your libraries to get rid of these issues.\n       \nIn addition to scanning your images manually with docker scan command on a CLI, you can also configure Docker Hub to scan the images automatically, when they get pushed to the repository. And of course you can integrate this check in your CI/CD pipeline when building your Docker images.\n\n\n****************************************************************************************\n\n## B. TIPS\nThe **--rm** flag in Docker is used to automatically **remove the container when it exits.** This is useful for running short-lived containers where you don't need to keep the container around after it has completed its task, thus helping to keep your system clean from unused containers.\n\n```\nCopy code\ndocker run --rm my-image\n```\n### PRUNE:\n  - **docker image prune** to clean up just \"dangling\" images\n  - **docker system prune** will clean up everything you're not currently using\n  - The big one is usually **docker image prune -a** which will remove all images you're not using.\n  - Use **docker system df** to see space usage.\n  - **Linux/macOS bash**, sh, zsh, and Windows Docker Toolbox Quickstart Terminal use: **$(pwd)** which means \"print working directory\".\n  - **For PowerShell** use: **${pwd}**\n  - **For cmd.exe** \"Command Prompt use: **%cd%**\n  - When running postgres, you'll need to either set a password, or tell it to allow any connection you need to either set a password with the environment variable:\n\nPOSTGRES_PASSWORD=mypasswd\n\nOr tell it to ignore passwords with the environment variable:\n\nPOSTGRES_HOST_AUTH_METHOD=trust\n\n-\u003e Use the command **ps aux** in each container to see a list of processes and usernames. The process needs a matching user ID or group ID to access the files in question.\nNote: If ps doesn't work in your container, you may need to install it. In debian-based images with apt, you can add it with apt-get update \u0026\u0026 apt-get install procps \n\n****************************************************************************************\n\n## C. BEST PRACTICE SAMPLES\n\n### 1 Rootless containers\n```\nFROM alpine:3.12\n# Create user and set ownership and permissions as required\nRUN adduser -D myuser \u0026\u0026 chown -R myuser /myapp-data\n# ... copy application files\nUSER myuser\nENTRYPOINT [\"/myapp\"]\n```\n\n### 2 Multistage builds\n\n```\n#This is the \"builder\" stage\nFROM golang:1.15 as builder\nWORKDIR /my-go-app\nCOPY app-src .\nRUN GOOS=linux GOARCH=amd64 go build ./cmd/app-service\n#This is the final stage, and we copy artifacts from \"builder\"\nFROM gcr.io/distroless/static-debian10\nCOPY --from=builder /my-go-app/app-service /bin/app-service\nENTRYPOINT [\"/bin/app-service\"]\n```\n\nSince RUN, COPY, ADD, and other instructions will create a new container layer, grouping multiple commands together will reduce the number of layers.\n - **For example, instead of:**\n```\nFROM ubuntu\nRUN apt-get install -y wget\nRUN wget https://…/downloadedfile.tar\nRUN tar xvzf downloadedfile.tar\nRUN rm downloadedfile.tar\nRUN apt-get remove wget\n```\n\n- **It would be a Dockerfile best practice to do:**\n```\nFROM ubuntu\nRUN apt-get install wget \u0026\u0026 wget https://…/downloadedfile.tar \u0026\u0026 tar xvzf downloadedfile.tar \u0026\u0026 rm downloadedfile.tar \u0026\u0026 apt-get remove wget \n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkgoksal%2Fdocker-best-practices","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkgoksal%2Fdocker-best-practices","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkgoksal%2Fdocker-best-practices/lists"}