Dockerfile¶
Dockerfile instructions¶
Reference: Dockerfile reference, Best practices for Dockerfile instructions
USER¶
Use the
user:group
form for the USER instruction, unless you want the group to beroot
.Use the name
runner
for the non-root user:RUN groupadd -r runner && useradd --no-log-init -r -g runner runner
WORKDIR¶
Use a leading
/
with theWORKDIR
instruction.Set WORKDIR to
/workdir
:WORKDIR /workdir
COPY¶
Use the
--chown=user:group
option with the COPY instruction, unless you want the ownership of the files to beroot:root
.Prefer the
COPY
instruction to the ADD instruction, as recommended.
Layer order¶
To leverage the build cache, order the instructions from least-to-most likely to change over time. In general, the order is:
Declare the base image
Install system packages
Create a non-root user
Copy requirements files
Install project dependencies
Set the working directory
Switch to the non-root user
Copy project files
Note
For Node, set the working directory before copying requirements files.
Base images¶
For Python, use the default image, as recommended, of the minor version, to ensure predictable behavior. Do not use the -slim
or -alpine
versions.
For Node, use the default image, as recommended, of the major version. Do not use the -slim
or -alpine
versions.
For a web server, use the nginxinc/nginx-unprivileged:latest image. Note that the default port is changed to 8080 (instead of 80).
Set server_tokens off;
to prevent false positives from penetration tests (Ubuntu backports security patches, without changing version numbers).
Note
For reference, the default /etc/nginx/conf.d/default.conf
file in the Nginx image is:
server {
listen 8080;
listen [::]:8080;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
See also
System packages¶
Before installing a system package, check whether it’s included in a base image. For example, the psycopg2
Python package requires the libpq-dev
system package. To check whether it’s included, when using the python:3.10 image:
Find the tag on the DockerHub page of the base image (the
3.10
tag is under Shared Tags)Click the link to view the Dockerfile
Check the
apt-get install
commands for the package nameIf not found, look for
FROM
instructionsRepeat from step 1 for the
FROM
image(s)
We find that the buildpack-deps:bullseye image installs the libpq-dev
system package.
If it’s not included, install it following best practices:
RUN apt-get update && apt-get install -y --no-install-recommends \
package-a \
package-b \
package-c \
&& rm -rf /var/lib/apt/lists/*
Bind mounts¶
Note
In general, do not use absolute paths on the host’s filesystem as an API between projects, because the projects might not share the same filesystem, like in the case of Docker containers. Instead, use paths relative to a configurable setting.
If a project needs to read or write data to the filesystem:
Add a setting with a default value. For example, for a Django project:
KINGFISHER_COLLECT_FILES_STORE = os.getenv( "KINGFISHER_COLLECT_FILES_STORE", "/data" if production else BASE_DIR / "data" )
Create the directory using the default value in the Dockerfile. For example:
# Must match the settings.KINGFISHER_COLLECT_FILES_STORE default value. RUN mkdir -p /data && chown -R runner:runner /data
Mount the host’s directory to the default value in the Docker Compose file. For example:
services: django: volumes: - /data/storage/kingfisher-collect:/data
If a project needs to read or write data to multiple directories, set the default values to subdirectories of the /data
directory.
Templates¶
Note
If Dockerfiles are similar across projects, we can consider creating our own base images and using the ONBUILD instruction to copy source code.
Python¶
FROM python:3.11
RUN groupadd -r runner && useradd --no-log-init -r -g runner runner
COPY requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir -r /tmp/requirements.txt
WORKDIR /workdir
USER runner:runner
COPY --chown=runner:runner . .
See also
Node¶
See: