Loading... ## 简介 Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令。 ## 基本结构 Dockerfile一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时的执行指令, `#`是Dockerfile中的注释。 Docker是以从上到下的顺序来运行Dockerfile的指令的,为了指定基本镜像,第一条指令必须是FROM ### FROM 用于指定基础镜像,必须为第一个命令 ``` 格式: FROM <image> FROM <image>:<tag> FROM <image>@<digest> 示例: FROM mysql:5.6 FROM scratch # 空 注: tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像 ``` ### MAINTAINER 维护者信息 ``` 格式: MAINTAINER <name> 示例: MAINTAINER Jasper Xu MAINTAINER sorex@163.com MAINTAINER Jasper Xu <sorex@163.com> ``` ### LABEL 为镜像添加元数据 ``` 格式: LABEL <key>=<value> <key>=<value> <key>=<value> ... 示例: LABEL version="1.0" description="这是一个Web服务器" by="IT笔录" 注: 使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。 ``` ### RUN RUN用于在镜像容器中执行命令,其有以下两种命令执行方式: ``` RUN用于在镜像容器中执行命令,其有以下两种命令执行方式: shell执行 格式: RUN <command> exec执行 格式: RUN ["executable", "param1", "param2"] 示例: RUN ["executable", "param1", "param2"] RUN apk update RUN ["/etc/execfile", "arg1", "arg1"] 注: RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache ``` ### ENV 设置环境变量 ``` 格式: ENV <key> <value> #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量 ENV <key>=<value> ... #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行 示例: ENV myName John Doe ENV myDog Rex The Dog ENV myCat=fluffy ``` ### ADD 将本地文件添加到容器中,tar类型会自动解压(网络压缩资源不会自动解压),支持访问网络资源 ``` 格式: ADD <src>... <dest> ADD ["<src>",... "<dest>"] 用于支持包含空格的路径 示例: ADD hom* /mydir/ # 添加所有以"hom"开头的文件 ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt" ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/ ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/ ``` ### COPY 类似于ADD的命令,但是不会自动解压文件,也不能访问网络资源。 ### ENTRYPOINT 和CMD差不多的命令 ``` 格式: ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先) ENTRYPOINT command param1 param2 (shell内部命令) 示例: FROM ubuntu ENTRYPOINT ["top", "-b"] CMD ["-c"] 注: ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。 ``` ### EXPOSE 指定容器与外界交互的端口 ``` 格式: EXPOSE <port> [<port>...] 示例: EXPOSE 80 443 EXPOSE 8080 EXPOSE 11211/tcp 11211/udp 注: EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口 ``` ### VOLUME 用于指定持久化目录,一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能: 1 卷可以容器间共享和重用 2 容器并不一定要和其它容器共享卷 3 修改卷后会立即生效 4 对卷的修改不会对镜像产生影响 5 卷会一直存在,直到没有任何容器在使用它 ``` 格式: VOLUME ["/path/to/dir"] 示例: VOLUME /data VOLUME ["/data"] VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"] ``` ### CMD 构建容器后调用,也就是容器启动时才进行调用的命令!! ``` 格式: CMD ["executable","param1","param2"] (执行可执行文件,优先) CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数) CMD command param1 param2 (执行shell内部命令) 示例: CMD echo "This is a test." | wc - CMD ["/usr/bin/wc","--help"] 注: CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。 ``` ## 一些示例 ### redis官方 dockerfile ```dockerfile FROM debian:bullseye-slim # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added RUN groupadd -r -g 999 redis && useradd -r -g redis -u 999 redis # grab 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 dirmngr gnupg 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 ENV REDIS_VERSION 6.2.6 ENV REDIS_DOWNLOAD_URL http://download.redis.io/releases/redis-6.2.6.tar.gz ENV REDIS_DOWNLOAD_SHA 5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab RUN set -eux; \ \ savedAptMark="$(apt-mark showmanual)"; \ apt-get update; \ apt-get install -y --no-install-recommends \ ca-certificates \ wget \ \ dpkg-dev \ gcc \ libc6-dev \ libssl-dev \ make \ ; \ rm -rf /var/lib/apt/lists/*; \ \ wget -O redis.tar.gz "$REDIS_DOWNLOAD_URL"; \ echo "$REDIS_DOWNLOAD_SHA *redis.tar.gz" | sha256sum -c -; \ mkdir -p /usr/src/redis; \ tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1; \ rm redis.tar.gz; \ \ # disable Redis protected mode [1] as it is unnecessary in context of Docker # (ports are not automatically exposed when running inside Docker, but rather explicitly by specifying -p / -P) # [1]: https://github.com/redis/redis/commit/edd4d555df57dc84265fdfb4ef59a4678832f6da grep -E '^ *createBoolConfig[(]"protected-mode",.*, *1 *,.*[)],$' /usr/src/redis/src/config.c; \ sed -ri 's!^( *createBoolConfig[(]"protected-mode",.*, *)1( *,.*[)],)$!\10\2!' /usr/src/redis/src/config.c; \ grep -E '^ *createBoolConfig[(]"protected-mode",.*, *0 *,.*[)],$' /usr/src/redis/src/config.c; \ # for future reference, we modify this directly in the source instead of just supplying a default configuration flag because apparently "if you specify any argument to redis-server, [it assumes] you are going to specify everything" # see also https://github.com/docker-library/redis/issues/4#issuecomment-50780840 # (more exactly, this makes sure the default behavior of "save on SIGTERM" stays functional by default) \ # https://github.com/jemalloc/jemalloc/issues/467 -- we need to patch the "./configure" for the bundled jemalloc to match how Debian compiles, for compatibility # (also, we do cross-builds, so we need to embed the appropriate "--build=xxx" values to that "./configure" invocation) gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \ extraJemallocConfigureFlags="--build=$gnuArch"; \ # https://salsa.debian.org/debian/jemalloc/-/blob/c0a88c37a551be7d12e4863435365c9a6a51525f/debian/rules#L8-23 dpkgArch="$(dpkg --print-architecture)"; \ case "${dpkgArch##*-}" in \ amd64 | i386 | x32) extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-page=12" ;; \ *) extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-page=16" ;; \ esac; \ extraJemallocConfigureFlags="$extraJemallocConfigureFlags --with-lg-hugepage=21"; \ grep -F 'cd jemalloc && ./configure ' /usr/src/redis/deps/Makefile; \ sed -ri 's!cd jemalloc && ./configure !&'"$extraJemallocConfigureFlags"' !' /usr/src/redis/deps/Makefile; \ grep -F "cd jemalloc && ./configure $extraJemallocConfigureFlags " /usr/src/redis/deps/Makefile; \ \ export BUILD_TLS=yes; \ make -C /usr/src/redis -j "$(nproc)" all; \ make -C /usr/src/redis install; \ \ # TODO https://github.com/redis/redis/pull/3494 (deduplicate "redis-server" copies) serverMd5="$(md5sum /usr/local/bin/redis-server | cut -d' ' -f1)"; export serverMd5; \ find /usr/local/bin/redis* -maxdepth 0 \ -type f -not -name redis-server \ -exec sh -eux -c ' \ md5="$(md5sum "$1" | cut -d" " -f1)"; \ test "$md5" = "$serverMd5"; \ ' -- '{}' ';' \ -exec ln -svfT 'redis-server' '{}' ';' \ ; \ \ rm -r /usr/src/redis; \ \ apt-mark auto '.*' > /dev/null; \ [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \ find /usr/local -type f -executable -exec ldd '{}' ';' \ | awk '/=>/ { print $(NF-1) }' \ | sort -u \ | xargs -r dpkg-query --search \ | cut -d: -f1 \ | sort -u \ | xargs -r apt-mark manual \ ; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ \ redis-cli --version; \ redis-server --version RUN mkdir /data && chown redis:redis /data VOLUME /data WORKDIR /data COPY docker-entrypoint.sh /usr/local/bin/ ENTRYPOINT ["docker-entrypoint.sh"] EXPOSE 6379 CMD ["redis-server"] ``` ### node ```dockerfile FROM alpine:3.11 ENV NODE_VERSION 16.10.0 RUN addgroup -g 1000 node \ && adduser -u 1000 -G node -s /bin/sh -D node \ && apk add --no-cache \ libstdc++ \ && apk add --no-cache --virtual .build-deps \ curl \ && ARCH= && alpineArch="$(apk --print-arch)" \ && case "${alpineArch##*-}" in \ x86_64) \ ARCH='x64' \ CHECKSUM="b4b00b3e9545f449620df3480bfd4c00b31c81d57b632a6138184d6afd70f09b" \ ;; \ *) ;; \ esac \ && if [ -n "${CHECKSUM}" ]; then \ set -eu; \ curl -fsSLO --compressed "https://unofficial-builds.nodejs.org/download/release/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz"; \ echo "$CHECKSUM node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" | sha256sum -c - \ && tar -xJf "node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \ && ln -s /usr/local/bin/node /usr/local/bin/nodejs; \ else \ echo "Building from source" \ # backup build && apk add --no-cache --virtual .build-deps-full \ binutils-gold \ g++ \ gcc \ gnupg \ libgcc \ linux-headers \ make \ python3 \ # gpg keys listed at https://github.com/nodejs/node#release-keys && for key in \ 4ED778F539E3634C779C87C6D7062848A1AB005C \ 94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \ 74F12602B6F1C4E913FAA37AD3A89613643B6201 \ 71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \ 8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 \ C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \ C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C \ DD8F2338BAE7501E3DD5AC78C273792F7D83545D \ A48C2BEE680E841632CD4E44F07496B3EB3C1762 \ 108F52B48DB57BB0CC439B2997B01419BD92F80A \ B9E2F5981AA6E0CD28160D9FF13993A75599653C \ ; do \ gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" || \ gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ done \ && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION.tar.xz" \ && curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ && grep " node-v$NODE_VERSION.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ && tar -xf "node-v$NODE_VERSION.tar.xz" \ && cd "node-v$NODE_VERSION" \ && ./configure \ && make -j$(getconf _NPROCESSORS_ONLN) V= \ && make install \ && apk del .build-deps-full \ && cd .. \ && rm -Rf "node-v$NODE_VERSION" \ && rm "node-v$NODE_VERSION.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt; \ fi \ && rm -f "node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz" \ && apk del .build-deps \ # smoke tests && node --version \ && npm --version ENV YARN_VERSION 1.22.5 RUN apk add --no-cache --virtual .build-deps-yarn curl gnupg tar \ && for key in \ 6A010C5166006599AA17F08146C2130DFD2497F5 \ ; do \ gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" || \ gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \ done \ && curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \ && curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz.asc" \ && gpg --batch --verify yarn-v$YARN_VERSION.tar.gz.asc yarn-v$YARN_VERSION.tar.gz \ && mkdir -p /opt \ && tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \ && ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \ && ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \ && rm yarn-v$YARN_VERSION.tar.gz.asc yarn-v$YARN_VERSION.tar.gz \ && apk del .build-deps-yarn \ # smoke test && yarn --version COPY docker-entrypoint.sh /usr/local/bin/ ENTRYPOINT ["docker-entrypoint.sh"] CMD [ "node" ] ``` ### ubuntu ``` FROM scratch ADD ubuntu-bionic-oci-amd64-root.tar.gz / CMD ["bash"] ``` 最后修改:2021 年 10 月 09 日 11 : 02 AM © 允许规范转载