什么是Dockerfile?
Dockerfile简介
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像时所需命令和容器运行时执行的指令和说明。
指令详解
FROM
构建镜像基于哪个镜像
例如,
FROM alpine:latest
MAINTAINER
镜像维护者姓名或邮箱地址,例如
MAINTAINER lady_killer9
WORKDIR
为 RUN、CMD、ENTRYPOINT、COPY 和 ADD 设置工作目录,就是切换目录,没有会自动创建,命令在该目录下执行。进入容器也是进入到此目录。例如,
WORKDIR /app
ADD(不推荐)
拷贝文件或目录到容器中,如果是URL或压缩包便会自动下载或自动解压
COPY(推荐)
拷贝文件或目录到容器中,跟ADD类似,但不具备自动下载或解压的功能。例如,
COPY src/ /app
RUN
构建镜像时运行的指令,例如
RUN pip install requests
CMD
运行容器时执行的命令,如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
CMD有三种形式
- CMD [“executable”,“param1”,“param2”] ,json数组
- CMD command param1 param2,shell形式
- CMD [“param1”,“param2”] ,作为 ENTRYPOINT的默认参数
例如,
CMD python3 test.py
注意:CMD命令执行的脚本等需要一直运行,否则创建容器后会很快停止。
ENTRYPOINT
ENTRYPOINT 有两种形式:
- ENTRYPOINT [“executable”, “param1”, “param2”] ,json数组
- ENTRYPOINT command param1 param2,shell形式
运行容器时执行,如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
CMD与ENTRYPOINT的情况(官方文档):
博主总结如下:
- CMD和ENTRYPOINT至少有一个
- 仅有一个时就按照这个命令
- 有两个时,ENTRYPOINT不是json数组形式,则以ENTRYPOINT为准
- 有两个时,若ENTRYPOINT与CMD都是json数组形式,则ENTRYPOINT与CMD拼接成shell形式
USER
为RUN、CMD、和 ENTRYPOINT 执行命令指定运行用户,一般不指定为root
EXPOSE
声明容器的服务端口
EXPOSE <port> [<port>/<protocol>...]
例如,
EXPOSE 80 EXPOSE 8080/http
之后run的时候可以配合-p参数映射到宿主机上
ENV
设置容器环境变量
ENV <key>=<value> ...
例如,
ENV JAVA_HOME=/home/myuser/jdk1.7.0_03
VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
VOLUME ["<路径1>", "<路径2>"...] VOLUME <路径>
例如,
VOLUME /var/log/nginx
Docker 命令
之前的文章Docker命令学习已经讲解了部分命令,但是构建等命令没有提及。
docker build
用于使用 Dockerfile 创建镜像。
docker build [OPTIONS] PATH | URL | -
OPTIONS说明:
- –build-arg=[] :设置镜像创建时的变量;
- –cpu-shares :设置 cpu 使用权重;
- –cpu-period :限制 CPU CFS周期;
- –cpu-quota :限制 CPU CFS配额;
- –cpuset-cpus :指定使用的CPU id;
- –cpuset-mems :指定使用的内存 id;
- –disable-content-trust :忽略校验,默认开启;
- -f :指定要使用的Dockerfile路径;
- –force-rm :设置镜像过程中删除中间容器;
- –isolation :使用容器隔离技术;
- –label=[] :设置镜像使用的元数据;
- -m :设置内存最大值;
- –memory-swap :设置Swap的最大值为内存+swap,"-1"表示不限swap;
- –no-cache :创建镜像的过程不使用缓存;
- –pull :尝试去更新镜像的新版本;
- –quiet, -q :安静模式,成功后只输出镜像 ID;
- –rm :设置镜像成功后删除中间容器;
- –shm-size :设置/dev/shm的大小,默认值是64M;
- –ulimit :Ulimit配置。
- –squash :将 Dockerfile 中所有的操作压缩为一层。
- –tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。
- –network: 默认 default。在构建期间设置RUN指令的网络模式
一般都是把Dockerfile放到项目里面,例如
docker build -t myapp:v1.0 .
docker commit
从容器创建一个新的镜像。
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
OPTIONS说明:
- -a :提交的镜像作者;
- -c :使用Dockerfile指令来创建镜像;
- -m :提交时的说明文字;
- -p :在commit时,将容器暂停。
docker save
将镜像输出到一个文件。
docker save [OPTIONS] IMAGE [IMAGE...]
OPTIONS 说明:
- -o :输出到的文件。
例如,
docker save -o myapp_v1.0.tar myapp:v1.0
docker load
从一个文件加载镜像
docker load [OPTIONS]
OPTIONS 说明:
- –input , -i : 指定导入的文件,代替 STDIN。
- –quiet , -q : 精简输出信息。
例如,
docker load -i myapp_v1.0.tar
Dockerfile举例
mysql debian
# # NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" # # PLEASE DO NOT EDIT IT DIRECTLY. # FROM debian:buster-slim # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added RUN groupadd -r mysql && useradd -r -g mysql mysql RUN apt-get update && apt-get install -y --no-install-recommends gnupg dirmngr && rm -rf /var/lib/apt/lists/* # add gosu for easy step-down from root # https://github.com/tianon/gosu/releases ENV GOSU_VERSION 1.14 RUN set -eux; \ savedAptMark="$(apt-mark showmanual)"; \ apt-get update; \ apt-get install -y --no-install-recommends ca-certificates wget; \ rm -rf /var/lib/apt/lists/*; \ dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ gpgconf --kill all; \ rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ apt-mark auto '.*' > /dev/null; \ [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ chmod +x /usr/local/bin/gosu; \ gosu --version; \ gosu nobody true RUN mkdir /docker-entrypoint-initdb.d RUN set -eux; \ apt-get update; \ apt-get install -y --no-install-recommends \ openssl \ # FATAL ERROR: please install the following Perl modules before executing /usr/local/mysql/scripts/mysql_install_db: # File::Basename # File::Copy # Sys::Hostname # Data::Dumper perl \ xz-utils \ zstd \ ; \ rm -rf /var/lib/apt/lists/* RUN set -eux; \ # gpg: key 3A79BD29: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported key='859BE8D7C586F538430B19C2467B942D3A79BD29'; \ export GNUPGHOME="$(mktemp -d)"; \ gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \ mkdir -p /etc/apt/keyrings; \ gpg --batch --export "$key" > /etc/apt/keyrings/mysql.gpg; \ gpgconf --kill all; \ rm -rf "$GNUPGHOME" ENV MYSQL_MAJOR 5.7 ENV MYSQL_VERSION 5.7.37-1debian10 RUN echo 'deb [ signed-by=/etc/apt/keyrings/mysql.gpg ] http://repo.mysql.com/apt/debian/ buster mysql-5.7' > /etc/apt/sources.list.d/mysql.list # the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) # also, we set debconf keys to make APT a little quieter RUN { \ echo mysql-community-server mysql-community-server/data-dir select ''; \ echo mysql-community-server mysql-community-server/root-pass password ''; \ echo mysql-community-server mysql-community-server/re-root-pass password ''; \ echo mysql-community-server mysql-community-server/remove-test-db select false; \ } | debconf-set-selections \ && apt-get update \ && apt-get install -y \ mysql-server="${MYSQL_VERSION}" \ # comment out a few problematic configuration values && find /etc/mysql/ -name '*.cnf' -print0 \ | xargs -0 grep -lZE '^(bind-address|log)' \ | xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/' \ # don't reverse lookup hostnames, they are usually another container && echo '[mysqld]\nskip-host-cache\nskip-name-resolve' > /etc/mysql/conf.d/docker.cnf \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql /var/run/mysqld \ && chown -R mysql:mysql /var/lib/mysql /var/run/mysqld \ # ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime && chmod 1777 /var/run/mysqld /var/lib/mysql VOLUME /var/lib/mysql COPY docker-entrypoint.sh /usr/local/bin/ RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat ENTRYPOINT ["docker-entrypoint.sh"] EXPOSE 3306 33060 CMD ["mysqld"]
这是mysql的官方Dockerfile,基于debian:buster-slim镜像,执行了一些命令,添加了环境变量GOSU_VERSION、MYSQL_VERSION 等,添加了匿名挂载卷/var/lib/mysql,复制了docker-entrypoint.sh脚本到 /usr/local/bin/下,运行脚本,暴露端口3306和33060。