最後更新: 2023-06-02
Dockerfile
A plain text file that specifies all of the components that are included in the container.
目錄
- INSTRUCTION
- 建立 Image
- Example
- Interactive
- Interrupting a podman build
- Log
INSTRUCTION
Dockerfile 指令的一般格式為
INSTRUCTION arguments
資訊類指令操作
MAINTAINER
維護者訊息
MAINTAINER STRING
LABEL
adds metadata to an image
LABEL <key1>=<value1> <key2>=<value2> ... LABEL <key1>=<value1> \ <key2>=<value2> \ ...
FROM
FROM <image> FROM <image>:<tag>
ENV
# 指定一個環境變數 (會被後續 RUN 指令使用)
ENV <key>=<value>
* The value will be interpreted for other environment variables
* quote characters will be removed if they are not escaped
SHELL
* SHELL is not supported for OCI image format, it will be ignored.
設定 RUN 時所用到的 Shell
SHELL ["executable", "parameters"] # Default '["/bin/sh", "-c"]'
* The SHELL instruction can appear multiple times. Each SHELL instruction overrides previous
RUN
# 每條 RUN 指令將在當前映像檔 "/" 上以 shell 執行
RUN <command>
# 用 exec 執行
RUN ["executable", "param1", "param2"]
# 行多行的 script
RUN <<EOT #!/usr/bin/env python print("hello world") EOT
WORKDIR
轉換在 CT 內的 PWD
影響 RUN, CMD, ENTRYPOINT, COPY and ADD
WORKDIR /var/log
log
STEP 10/14: WORKDIR /var/log --> Using cache 563cb0a7637b31d9c37411344d7e418555f17032d0a8c576f348657a5838e70b --> 563cb0a7637
Remark
- If not specified, the default working directory is "/"
- The WORKDIR instruction can be used multiple times in a Dockerfile.
- If a relative path is provided, it will be relative to the path of the previous WORKDIR instruction.
- The WORKDIR instruction can resolve environment variables previously set using ENV.
EXPOSE
# 設定 Docker Container 對外的 Port
EXPOSE <port> [<port>...]
* The EXPOSE instruction defines metadata only
(it does not make ports accessible from the host.)
* "docker run -P ... " 時, Docker 會自動分配其他 port 並 NAT 到 EXPOSE 的 port
( 如果要指定 Port 就要用 -p option )
CMD
# 指定啟動容器時執行的命令
* 每個 Dockerfile 只可以有一個 CMD (最後一條會被執行)
* CMD does not execute anything at build time, but specifies the intended command for the image.
# 使用 exec 執行
CMD ["executable","param1","param2"]
CMD 與 ENTRYPOINT
如果同時定義了 CMD 和 ENTRYPOINT, 則 CMD 會被當作 ENTRYPOINT 的默認參數
* CMD 只是作為 ENTRYPOINT 所需的預設參數
行 system service 的 CMD
CMD ["tail", "-F", "/dev/null"]
P.S. "podman exec CT_NAME ps aux" 入去看
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 2888 1040 ? Ss 09:41 0:00 /bin/sh -c tail -F /dev/null root 7 0.0 0.0 2820 1040 ? S 09:41 0:00 tail -F /dev/null
COPY [--chown=<user>:<group>] [--chmod=<perms>] <src>... <dest>
# 支援 "*", "?"
COPY *.txt /mydir/
# adds "test.txt" to <WORKDIR>/relativeDir/
COPY test.txt relativeDir/
注意
<src>
* The <src> path must be inside the context of the build; you cannot COPY ../something /something
* If <src> is a directory, the entire contents of the directory are copied
(The directory itself is not copied, just its contents.)
* If <src> is any other kind of file, if <dest> ends with a trailing slash / , <src> will be written at <dest>/base(<src>)
* If multiple <src>
resources are specified, either directly or due to the use of a wildcard,
then <dest>
must be a directory, and it must end with a slash/
<dest>
* If <dest> does not end with a trailing slash,
it will be considered a regular file and the contents of <src> will be written at <dest>
* If <dest> doesn't exist, it is created along with all missing directories in its path.
ADD
# 複製指定的 <src> 到容器中的 <dest>
# src 可以是 Dockerfile 所在目錄的相對路徑
# 當 src 是 .tar.gz 檔時, 其複製後會自動解壓縮
# 當 src 是 URL 時, 會自動下載
ADD [--chown=<user>:<group>] [--chmod=<perms>] [--checksum=<checksum>] <src>... <dest>
Opts
- --checksum=sha256:...
ADD by Git
ADD [--keep-git-dir=<boolean>] <git ref> <dir> ADD [email protected]:foo/bar.git /bar
COPY vs ADD
The major difference is that ADD can do more than COPY
ARG
Instruction defines a variable that users can pass at build-time to the builder
yml
ARG <name>[=<default value>]
build-time input: --build-arg <varname>=<value>
引用: $varname / ${varname}
i.e.
# 使用 ARG 設定 ENV
FROM ubuntu ARG CONT_IMG_VER ENV CONT_IMG_VER=${CONT_IMG_VER:-v1.0.0} RUN echo $CONT_IMG_VER
建立 Image
dnf install podman -y
mkdir mylamp; cd !$
vim Dockerfile
podman build -t t1: .
podman images
REPOSITORY TAG IMAGE ID CREATED SIZE localhost/t1 latest f6dfed79d98f 4 minutes ago 230 MB
podman run localhost/t1
P.S.
# 指定 build 那一個 file 並設定它的 tag
podman build -t t1:v2 -f Dockerfile.v2
Example
[1A]
FROM ubuntu:22.04 # Install dependencies RUN apt-get update && \ apt-get -y install apache2 # Install apache and write hello world message RUN echo 'Hello World!' > /var/www/html/index.html # Configure apache #RUN echo '. /etc/apache2/envvars' > /root/run_apache.sh && \ # echo 'mkdir -p /var/run/apache2' >> /root/run_apache.sh && \ # echo 'mkdir -p /var/lock/apache2' >> /root/run_apache.sh && \ # echo '/usr/sbin/apache2 -D FOREGROUND' >> /root/run_apache.sh && \ # chmod 755 /root/run_apache.sh #CMD /root/run_apache.sh EXPOSE 80
[1B]
[2]
FROM debian:jessie MAINTAINER NGINX Docker Maintainers "[email protected]" ENV NGINX_VERSION 1.11.5-1~jessie RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 \ && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list \ && apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y \ ca-certificates \ nginx=${NGINX_VERSION} \ nginx-module-xslt \ nginx-module-geoip \ nginx-module-image-filter \ nginx-module-perl \ nginx-module-njs \ gettext-base \ && rm -rf /var/lib/apt/lists/* # forward request and error logs to docker log collector RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log EXPOSE 80 443 CMD ["nginx", "-g", "daemon off;"]
-g directives Set global configuration directives.
Interrupting a podman build
podman images
<none> <none> 54f788544499 37 minutes ago 231 MB
podman rmi 54f788544499
image is in use by a container: consider listing external containers and force-removing image
podman ps --all
podman ps --all --storage
container running by COMMAND buildah
Fix
podman rm --force ID
Troubleshoot build Fail
podman run -it --name test ubuntu:22.04 /bin/bash
一步步行 CLI
podman rm podman
Log
# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log
在 container 內, nginx 需要以 CMD 啟動才得.
因為 docker log 係食 pid 1 的 stdout 及 stderr
ls -l /dev/std*
lrwxrwxrwx 1 root root 15 Jun 6 06:55 /dev/stderr -> /proc/self/fd/2 lrwxrwxrwx 1 root root 15 Jun 6 06:55 /dev/stdin -> /proc/self/fd/0 lrwxrwxrwx 1 root root 15 Jun 6 06:55 /dev/stdout -> /proc/self/fd/1
self
magic symbolic link, it resolves to the process's own /proc/[pid] directory
執行中的 CMD. cat 會是 cat. 測試 'cat /proc/self/comm'
healthcheck
Default
- interval: 30s
- timeout: 30s
- start_period: 30s
- retries: 3
start_period:
added in file format 3.4. initialization time for containers that need time to bootstrap
docker-compose.yml
healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 1m30s timeout: 10s start_period: 40s retries: 3
Dockerfile
Syntax
# running a command inside the container
HEALTHCHECK [OPTIONS] CMD command
# disable any healthcheck inherited from the base image
HEALTHCHECK NONE
exit status
0: success - the container is healthy and ready for use
1: unhealthy - the container is not working correctly
log
text (UTF-8 encoded) that the command writes on stdout or stderr will be stored in the health status (max: 4k)
checking: docker inspect CT
OPTIONS
- --interval=DURATION
- --timeout=DURATION
- --start-period=DURATION
- --retries=N
i.e.
HEALTHCHECK --interval=1m --timeout=3s \ CMD curl -f http://localhost/ || exit 1
建立 Ubuntu Docker Image
apt-get update
對應的 cleanup
rm -rf /var/lib/apt/lists/*
apt-get upgrade
對應的 cleanup
apt-get clean all
# clean clears out the local repository of retrieved package files.
# It removes everything but the lock file from /var/cache/apt/archives/ and /var/cache/apt/archives/partial/
apt-get 的 interactive 安裝
i.e. 安裝時 tzdata 會遇到的問題
apt-get -y install tzdata
即使設定了 "ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone"
當沒有 tzdata package 也是會錯 timezone 的
log
debconf: (TERM is not set, so the dialog frontend is not usable.)
Fix
[方案A]
ENV DEBIAN_FRONTEND noninteractive
[方案B]
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install tzdata
設定使用 bash Shell
ln -sf /usr/bin/bash /bin/sh