docker学习Dockerfile写作

Posted 懒佯佯大哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了docker学习Dockerfile写作相关的知识,希望对你有一定的参考价值。

介绍

  • Dockerfile是镜像制作的脚本,定义了镜像制作的过程

一个简单的示例:

  • 创建一个空目录/tmp/test/:用于存放镜像构建相关文件
  • 在该目录下,编写一个Dockerfile
zhaoyue@zhaoyuedeMacBook-Pro test % cat Dockerfile 
FROM scratch
CMD /bin/bash
  • 开始构建镜像
zhaoyue@zhaoyuedeMacBook-Pro test % docker build -f Dockerfile -t firstimage:1.0.0 .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM scratch		
# 父镜像。scratch是base镜像,所有镜像的祖先,类似于java中的Object类一样
# DockerHub中很多镜像,都是以此镜像为基础
 ---> 
Step 2/2 : CMD /bin/bash
 ---> Running in 7e3d94cf1358	# 每个命令都是一层layer
Removing intermediate container 7e3d94cf1358
 ---> fc0f384a1368
Successfully built fc0f384a1368
Successfully tagged firstimage:1.0.0
  • docker images:查看制作的镜像
zhaoyue@zhaoyuedeMacBook-Pro test % docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
firstimage          1.0.0               fc0f384a1368        7 minutes ago       0B

参数详细介绍

  • 官方文档:https://docs.docker.com/engine/reference/builder/

  • .dockerignore文件,定义了制作时忽略的文件列表(类似于git里的.gitignore)

  • 解释器参数,不会生成layer,这里不做详细介绍

    • directive=value

  • FROM:当前构建的基础镜像来源,可指定架构信息

    • FROM [–platform=] [AS ]
  • ARG:定义构建时的变量:

    • 格式:ARG [=]
    • docker在运行时可以通过:docker build --build-args xx=yy方式指定
    • 另外,dockerfile已经预定了一些变量名称,可以直接使用:HTTP_PROXY、http_proxy、HTTPS_PROXY、https_proxy、FTP_PROXY、ftp_proxy、NO_PROXY、no_proxy
  • MAINTAIN:作者,一般包括姓名、邮箱—-已经弃用,官方建议使用LABEL

  • RUN:执行linux命令

    • 格式1:RUN (shell形式,命令在shell中运行,默认情况下/bin/sh -c在Linux或cmd /S /CWindows 上运行)
    • 格式2:RUN [“executable”, “param1”, “param2”]
    • 由于每个命令都会生成一层layer,故多个命令时,建议使用&&进行连接,从而减少layer层数,便于维护
  • EXPOSE:该镜像启动时对外暴露的端口,可以通过protocol指定是TCP还是UDP

    • EXPOSE [/…]
  • LABEL:向镜像中添加的元数据信息(多个key-value数据时,尽量合并成一行),可以通过docker inspect命令查看LABEL的信息

    • LABEL = = = …
  • WORKDIR:创建容器后,终端默认登录进来的工作目录,如果没设置的话,则为根目录

  • ENV:设置环境变量,该命令也会生成layer,示例:ENV MY_PATH /home/admin

    • ENV
    • ENV = … # 这种可以设置多个值
    • 也可通过docker run —env =动态修改
  • ADD:将宿主机的文件“拷贝+解压”(gzip,bzip2或xz)进镜像

    • ADD [–chown=:] …
    • ADD [–chown=:] ["",… “”]
    • src路径设置的时候,可以按照Go的 filepath.Match通配规则
    • 示例:ADD --chown=55:mygroup files* /somedir/
  • COPY:将宿主机的文件“拷贝”进镜像

    • COPY [–chown=:] …
    • COPY [–chown=:] ["",… “”]
    • 备注:src中可含有满足filepath.Match的通配符
  • VOLUME:容器数据卷,用于保存和持久化操作

    • 为了保证可移植性,这里只需指定容器中的路径,docker会在本地的默认路径生成一个映射目录
  • ONBUILD:当构建一个被继承的Dockerfile时运行:父镜像在被子镜像继承后会被触发

  • USER:指定运行命令的用户/组

    • USER [:] group为可选
  • STOPSIGNAL

    • STOPSIGNAL signal
    • 该STOPSIGNAL指令设置将被发送到容器退出的系统调用信号。该信号可以是与内核syscall表中的位置匹配的有效无符号数字(例如9),也可以是格式为SIGNAME的信号名称(例如SIGKILL)。
  • CMD:容器启动时的运行命令以及参数,存在多个时只有最后一个生效

    • CMD [“executable”,“param1”,“param2”](exec形式,这是首选形式)
    • CMD [“param1”,“param2”](作为ENTRYPOINT的默认参数)
    • CMD command param1 param2(外壳形式
    • docker run时可加上命令,此时会覆盖掉CMD:docker run nginx ls
  • ENTRYPOINT:容器启动时的运行命令以及参数

    • 可以通过docker run --entrypoint 覆盖执行
    • ENTRYPOINT [“executable”, “param1”, “param2”]
    • ENTRYPOINT command param1 param2
    • 示例:ENTRYPOINT exec top -b

部分参数差异

  • ARG vs ENV:
    • ENV声明的变量,会始终存在于环境中
    • 同名的情况下,ENV声明的覆盖掉ARG
    • ARG用于build阶段,用–build-arg修改
    • ENV用于run阶段,用–env修改
  • CMD vs ENTRYPOINT:
    • CMD的命令会被覆盖,以最后一个为准
    • ENTRYPOINT会被追加,逐步追加到之前的命令上,然后作为一条完整命令执行
    • 可以同时使用,一般将CMD写在后面,容器启动时,是将ENTRYPOINT和CMD的命令拼在一起执行,这样,既保证了ENTRYPOINT的灵活,也可保证CMD的唯一性

官网的示例

  1. 登录官网:hub.docker.com
  2. 搜索需要查找的镜像
  3. 进入查找的镜像,然后选中某一个版本,比如latest
  4. 示例1:centos
    • https://github.com/CentOS/sig-cloud-instance-images/blob/52cc14a6dd2efc45265417a4690964d32cf13857/docker/Dockerfile
# 基础镜像
FROM scratch
# 将centos镜像拷贝、解压到根目录
ADD CentOS-8-Container-8.1.1911-20200113.3-layer.x86_64.tar.xz  /
# 元数据信息
LABEL org.label-schema.schema-version="1.0" \\
    org.label-schema.name="CentOS Base Image" \\
    org.label-schema.vendor="CentOS" \\
    org.label-schema.license="GPLv2" \\
    org.label-schema.build-date="20200114" \\
    org.opencontainers.image.title="CentOS Base Image" \\
    org.opencontainers.image.vendor="CentOS" \\
    org.opencontainers.image.licenses="GPL-2.0-only" \\
    org.opencontainers.image.created="2020-01-14 00:00:00-08:00"
#  启动命令
CMD ["/bin/bash"]
  1. 示例2:mysql
    • https://github.com/docker-library/mysql/blob/bc6e37a2bed792b1c4fc6ab1ec3ce316e6a5f061/8.0/Dockerfile
# debian镜像
FROM debian:buster-slim

# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
# 创建mysql的用户名、用户组
RUN groupadd -r mysql && useradd -r -g mysql mysql
# 执行apt-get命令安装相关依赖
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.12
# 安装相关软件
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
# 安装mysql
RUN apt-get update && apt-get install -y --no-install-recommends \\
# for MYSQL_RANDOM_ROOT_PASSWORD
		pwgen \\
# for mysql_ssl_rsa_setup
		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 \\
# install "xz-utils" for .sql.xz docker-entrypoint-initdb.d files
		xz-utils \\
	&& rm -rf /var/lib/apt/lists/*

RUN set -ex; \\
# gpg: key 5072E1F5: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported
	key='A4A9406876FCBD3C456770C88C718D3B5072E1F5'; \\
	export GNUPGHOME="$(mktemp -d)"; \\
	gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \\
	gpg --batch --export "$key" > /etc/apt/trusted.gpg.d/mysql.gpg; \\
	gpgconf --kill all; \\
	rm -rf "$GNUPGHOME"; \\
	apt-key list > /dev/null
# 设置环境变量
ENV MYSQL_MAJOR 8.0
ENV MYSQL_VERSION 8.0.20-1debian10

RUN echo "deb http://repo.mysql.com/apt/debian/ buster mysql-$MYSQL_MAJOR" > /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-community-client="$MYSQL_VERSION" mysql-community-server-core="$MYSQL_VERSION" && 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 777 /var/run/mysqld
# 挂卷信息,防止数据丢失!!!!
VOLUME /var/lib/mysql
# Config files
#  config配置
COPY config/ /etc/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"]
# 对外暴露的mysql端口
EXPOSE 3306 33060
CMD ["mysqld"]

延伸:

  • 构建加速:从版本18.09开始,Docker支持由moby / buildkit 项目提供的用于执行构建的新后端

以上是关于docker学习Dockerfile写作的主要内容,如果未能解决你的问题,请参考以下文章

Docker学习笔记-- 如何使用Dockerfile构建镜像

docker学习笔记——Dockerfile创建自定义镜像

Docker学习笔记-- 如何使用Dockerfile构建镜像

docker学习笔记 --- Dockerfile解析

docker学习:DockerFile微服务实战及docker端口映射

004Docker学习__Dockerfile_build命令构建docker镜像