构建 Docker 镜像的 小技巧

本文分享了构建高效Docker镜像的实用技巧,包括优化构建上下文、选择合适的基础镜像、使用国内镜像站加速构建过程、合理设置时区、减少镜像层数等方面的经验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

构建镜像的几个小技巧

构建上下文

执行 docker build 命令时,当前的工作目录被称为构建上下文。默认情况下,Dockerfile 就位于该路径下。也可以通过 -f 参数来指定 dockerfile ,但 docker 客户端会将当前工作目录下的所有文件发送到 docker 守护进程进行构建。

所以来说,当执行 docker build 进行构建镜像时,当前目录一定要 干净 ,切记不要在家里录下创建一个 Dockerfile 紧接着 docker build 一把梭 😂。

正确做法是为项目建立一个文件夹,把构建镜像时所需要的资源放在这个文件夹下。比如这样:

mkdir projectcd !$vi Dockerfile# 编写 Dockerfile

也可以通过 .dockerignore 文件来忽略不需要的文件发送到 docker 守护进程

基础镜像

使用体积较小的基础镜像,比如 alpine 或者 debian:buster-slim,像 openjdk 可以选用 openjdk:xxx-slim,由于 openjdk 是基于 debian 的基础镜像构建的,所以向 debian 基础镜像一样,后面带个 slim 就是基于 debian:xxx-slim 镜像构建的。​​​​​​​

REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZEdebian                      buster-slim         e1af56d072b8        4 days ago          69.2MBalpine                      latest              cc0abc535e36        8 days ago          5.59MB

不过需要注意的是,alpine 的 c 库是 musl libc ,而不是正统的 glibc,另外对于一些依赖 glibc 的大型项目,像 openjdk 、tomcat、rabbitmq 等都不建议使用 alpine 基础镜像,因为 musl libc 可能会导致 JVM 一些奇怪的问题。这也是为什么 tomcat 官方没有给出基础镜像是 alpine 的 Dockerfile 的原因。

国内软件源

使用默认的软件源安装构建时所需的依赖,对于绝大多数基础镜像来说,可以通过修改软件源的方式更换为国内的软件源镜像站。目前国内稳定可靠的镜像站主要有,华为云、阿里云、腾讯云、163 等。

  • 对于 alpine 基础镜像修改软件源​​​​​​​

echo "http://mirrors.huaweicloud.com/alpine/latest-stable/main/" > /etc/apk/repositories ;\echo "http://mirrors.huaweicloud.com/alpine/latest-stable/community/" >> /etc/apk/repositories ;\apk update ;
  • debian 基础镜像修改默认原件源码​​​​​​​

sed -i 's/deb.debian.org/mirrors.huaweicloud.com/g' /etc/apt/sources.list ;\sed -i 's|security.debian.org/debian-security|mirrors.huaweicloud.com/debian-security|g' /etc/apt/sources.list ;\apt update ;\
  • Ubuntu 基础镜像修改默认原件源码​​​​​​​

sed -i 's/archive.ubuntu.com/mirrors.huaweicloud.com/g' /etc/apt/sources.listapt update ;\
  • 对于 CentOS ???

你确定要用 220MB 大小的基础镜像?​​​​​​​

REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZEcentos                      latest              0f3e07c0138f        3 months ago        220MB

建议这些命令就放在 RUN 指令的第一条,update 以下软件源,之后再 install 相应的依赖。

时区设置

由于绝大多数基础镜像都是默认采用 UTC 的时区,与北京时间相差 8 个小时,这将会导致容器内的时间与北京时间不一致,因而会对一些应用造成一些影响,还会影响容器内日志和监控的数据。

因此对于东八区的用户,最好在构建镜像的时候设定一下容器内的时区,以免以后因为时区遇到一些 bug😂。

可以通过环境变量设置容器内的时区。在启动的时候可以通过设置环境变量 -e TZ=Asia/Shanghai 来设定容器内的时区。

alpine

  • 但对于 alpine 基础镜像无法通过 TZ 环境变量的方式设定时区,需要安装 tzdata 来配置时区。​​​​​​​

root@ubuntu:~/docke/alpine# docker run --rm -it -e TZ=Asia/Shanghai alpine dateThu Jan  2 03:37:44 UTC 2020
  • 对于 alpine 基础镜像,可以在 RUN 指令后面追加上以下命令​​​​​​​

apk add --no-cache tzdata ;\cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ;\echo "Asia/Shanghai" > /etc/timezone ;\apk del tzdata ;\
  • 通过 tzdate 设定时区​​​​​​​

root@ubuntu:~/docke/alpine# docker build -t alpine:tz2 .Sending build context to Docker daemon  2.048kBStep 1/2 : FROM alpine ---> cc0abc535e36Step 2/2 : RUN set -xue ;    echo "http://mirrors.huaweicloud.com/alpine/latest-stable/main/" > /etc/apk/repositories ;    echo "http://mirrors.huaweicloud.com/alpine/latest-stable/community/" >> /etc/apk/repositories ;    apk update ;    apk add --no-cache tzdata ;    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ;    echo "Asia/Shanghai" > /etc/timezone ;    apk del tzdata ---> Running in 982041a34dbf+ echo http://mirrors.huaweicloud.com/alpine/latest-stable/main/+ echo http://mirrors.huaweicloud.com/alpine/latest-stable/community/+ apk updatefetch http://mirrors.huaweicloud.com/alpine/latest-stable/main/x86_64/APKINDEX.tar.gzfetch http://mirrors.huaweicloud.com/alpine/latest-stable/community/x86_64/APKINDEX.tar.gzv3.11.2-11-gd5cdcefa20 [http://mirrors.huaweicloud.com/alpine/latest-stable/main/]v3.11.2-14-g973431591e [http://mirrors.huaweicloud.com/alpine/latest-stable/community/]OK: 11261 distinct packages available+ apk add --no-cache tzdatafetch http://mirrors.huaweicloud.com/alpine/latest-stable/main/x86_64/APKINDEX.tar.gzfetch http://mirrors.huaweicloud.com/alpine/latest-stable/community/x86_64/APKINDEX.tar.gz(1/1) Installing tzdata (2019c-r0)Executing busybox-1.31.1-r8.triggerOK: 9 MiB in 15 packages+ cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime+ echo Asia/Shanghai+ apk del tzdata(1/1) Purging tzdata (2019c-r0)Executing busybox-1.31.1-r8.triggerOK: 6 MiB in 14 packagesRemoving intermediate container 982041a34dbf ---> 3ec89f3e824dSuccessfully built 3ec89f3e824dSuccessfully tagged alpine:tz2root@ubuntu:~/docke/alpine# docker run --rm -it alpine:tz2 dateThu Jan  2 11:12:23 CST 2020

debian

  • 通过启动时设定环境变量指定时区​​​​​​​

root@ubuntu:~/docke/alpine# docker run --rm -it -e TZ=Asia/Shanghai debian dateThu Jan  2 11:38:56 CST 2020
  • 也可以再构建镜像的时候复制时区文件设定容器内时区

cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ;\echo "Asia/shanghai" > /etc/timezone ;\

ubuntu

  • 通过启动时设定环境变量指定时区,发射失败 😂,只能通过时区文件来设定时区了。


root@ubuntu:~/docke/alpine# docker run --rm -it -e TZ=Asia/Shanghai debian dateThu Jan  2 11:38:56 CST 2020
root@ubuntu:~/docke/alpine# ^debian^ubuntudocker run --rm -it -e TZ=Asia/Shanghai ubuntu dateThu Jan  2 03:44:13 Asia 2020

在这里有个命令执行的小技巧,通过脱字符 ^ 来替换上一条命令中的 debian 为 ubuntu 然后执行相同的命令。

  • 通过时区文件来设定时区

apt update ;\apt install tzdata -y ;\cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ;\echo "Asia/shanghai" > /etc/timezone ;\

尽量使用 URL 添加源码

如果不采用分阶段构建,对于一些需要在容器内进行编译的项目,最好通过 git 或者 wegt 的方式将源码打入到镜像内,而非采用 ADD 或者 COPY ,因为源码编译完成之后,源码就不需要可以删掉了,而通过 ADD 或者 COPY 添加进去的源码已经用在下一层镜像中了,是删不掉滴啦。

也就是说 git & wget source 然后 build,最后 rm -rf source/ 这三部放在一条 RUN 指令中,这样就能避免源码添加到镜像中而增大镜像体积啦。

下面以 FastDFS 的 Dockerfile 为例:

  • 项目官方的 Dockerfile

# centos 7FROM centos:7# 添加配置文件# add profilesADD conf/client.conf /etc/fdfs/ADD conf/http.conf /etc/fdfs/ADD conf/mime.types /etc/fdfs/ADD conf/storage.conf /etc/fdfs/ADD conf/tracker.conf /etc/fdfs/ADD fastdfs.sh /homeADD conf/nginx.conf /etc/fdfs/ADD conf/mod_fastdfs.conf /etc/fdfs
# 添加源文件# add source codeADD source/libfastcommon.tar.gz /usr/local/src/ADD source/fastdfs.tar.gz /usr/local/src/ADD source/fastdfs-nginx-module.tar.gz /usr/local/src/ADD source/nginx-1.15.4.tar.gz /usr/local/src/
# RunRUN yum install git gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl-devel wget vim -y \  &&  mkdir /home/dfs   \  &&  cd /usr/local/src/  \  &&  cd libfastcommon/   \  &&  ./make.sh && ./make.sh install  \  &&  cd ../  \  &&  cd fastdfs/   \  &&  ./make.sh && ./make.sh install  \  &&  cd ../  \  &&  cd nginx-1.15.4/  \  &&  ./configure --add-module=/usr/local/src/fastdfs-nginx-module/src/   \  &&  make && make install  \  &&  chmod +x /home/fastdfs.sh# export configVOLUME /etc/fdfs
EXPOSE 22122 23000 8888 80ENTRYPOINT ["/home/fastdfs.sh"]
  • 经过本人优化后的 Dockerfile

FROM alpine:3.10
RUN set -x \    && echo "http://mirrors.huaweicloud.com/alpine/latest-stable/main/" > /etc/apk/repositories \    && echo "http://mirrors.huaweicloud.com/alpine/latest-stable/community/" >> /etc/apk/repositories \    && apk update \    && apk add --no-cache --virtual .build-deps gcc libc-dev make perl-dev openssl-dev pcre-dev zlib-dev git \    && mkdir -p /usr/local/src \    && cd /usr/local/src \    && git clone https://github.com/happyfish100/libfastcommon.git --depth 1 \    && git clone https://github.com/happyfish100/fastdfs.git --depth 1    \    && git clone https://github.com/happyfish100/fastdfs-nginx-module.git --depth 1  \    && wget http://nginx.org/download/nginx-1.15.4.tar.gz \    && tar -xf nginx-1.15.4.tar.gz \    && cd /usr/local/src/libfastcommon \    && ./make.sh \    && ./make.sh install \    && cd /usr/local/src/fastdfs/ \    && ./make.sh \    && ./make.sh install \    && cd /usr/local/src/nginx-1.15.4/ \    && ./configure --add-module=/usr/local/src/fastdfs-nginx-module/src/ \    && make && make install \    && apk del .build-deps \    && apk add --no-cache pcre-dev bash \    && mkdir -p /home/dfs  \    && mv /usr/local/src/fastdfs/docker/dockerfile_network/fastdfs.sh /home \    && mv /usr/local/src/fastdfs/docker/dockerfile_network/conf/* /etc/fdfs \    && chmod +x /home/fastdfs.sh \    && rm -rf /usr/local/src*VOLUME /home/dfsEXPOSE 22122 23000 8888 8080CMD ["/home/fastdfs.sh"]
  • 构建之后的对比

使用项目默认的 Dockerfile 进行构建的话,镜像大小接近 500MB,而经过一些的优化,将所有的 RUN 指令合并为一条,最终构建出来的镜像大小为 30MB。

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZEfastdfs             alpine              e855bd197dbe        10 seconds ago      29.3MBfastdfs             debian              e05ca1616604        20 minutes ago      103MBfastdfs             centos              c1488537c23c        30 minutes ago      483MB

使用虚拟编译环境

对于只在编译过程中使用到的依赖,我们可以将这些依赖安装在虚拟环境中,编译完成之后可以一并删除这些依赖,比如 alpine 中可以使用 apk add --no-cache --virtual .build-deps,后面加上需要安装的相关依赖。


apk add --no-cache --virtual .build-deps gcc libc-dev make perl-dev openssl-dev pcre-dev zlib-dev git

构建完成之后可以使用 apk del .build-deps 命令,一并将这些编译依赖全部删除。

需要注意的是,.build-deps 后面接的是编译时以来的软件包,并不是所有的编译依赖都可以删除,不要把运行时的依赖包接在后面,最好单独 add 一下。

最小化层数

docker 在 1.10 以后,只有 RUN、COPY 和 ADD 指令会创建层,其他指令会创建临时的中间镜像,但是不会直接增加构建的镜像大小了。

前文提到了建议使用 git 或者 wget 的方式来将文件打入到镜像当中,但如果我们必须要使用 COPY 或者 ADD 指令呢?

还是拿 FastDFS 为例:

# centos 7FROM centos:7# 添加配置文件# add profilesADD conf/client.conf /etc/fdfs/ADD conf/http.conf /etc/fdfs/ADD conf/mime.types /etc/fdfs/ADD conf/storage.conf /etc/fdfs/ADD conf/tracker.conf /etc/fdfs/ADD fastdfs.sh /homeADD conf/nginx.conf /etc/fdfs/ADD conf/mod_fastdfs.conf /etc/fdfs
# 添加源文件# add source codeADD source/libfastcommon.tar.gz /usr/local/src/ADD source/fastdfs.tar.gz /usr/local/src/ADD source/fastdfs-nginx-module.tar.gz /usr/local/src/ADD source/nginx-1.15.4.tar.gz /usr/local/src/

多个文件需要添加到容器中不同的路径,每个文件使用一条 ADD 指令的话就会增加一层镜像,这样戏曲就多了 12 层镜像 。其实大可不必,我们可以将这些文件全部打包为一个文件为 src.tar.gz 然后通过 ADD 的方式把文件添加到当中去,然后在 RUN 指令后使用 mv 命令把文件移动到指定的位置。这样仅仅一条 ADD 和 RUN 指令取代掉了 12 个 ADD 指令。

FROM alpine:3.10COPY src.tar.gz /usr/local/src.tar.gzRUN set -xe \    && apk add --no-cache --virtual .build-deps gcc libc-dev make perl-dev openssl-dev pcre-dev zlib-dev tzdata \    && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \    && tar -xvf /usr/local/src.tar.gz -C /usr/local \    && mv /usr/local/src/conf/fastdfs.sh /home/fastdfs/ \    && mv /usr/local/src/conf/* /etc/fdfs \    && chmod +x /home/fastdfs/fastdfs.sh \    && rm -rf /usr/local/src/* /var/cache/apk/* /tmp/* /var/tmp/* $HOME/.cacheVOLUME /var/fdfs

其他最小化层数无非就是把构建项目的整个步骤弄成一条 RUN 指令,不过多条命令合并可以使用 && 或者 ; 这两者都可以,不过据我在 docker hub 上的所见所闻,使用 ; 的居多,尤其是官方的 Dockerfile。

文章略有精简。

文章转载:https://blog.k8s.li/dockerfile-tips.html

<think>好的,用户想在Linux环境下学习如何构建Docker镜像,我需要根据提供的引用内容来解答。首先,我需要回忆Docker镜像构建的基本步骤和相关命令。 根据引用[2],用户需要使用docker build命令和Dockerfile文件。Dockerfile里的指令是关键,所以应该详细说明如何编写这个文件。比如FROM指令指定基础镜像,RUN用来执行命令,COPY或ADD添加文件,CMD设置启动命令。 然后,引用[1]提到通过docker create启动容器并修改,但可能用户需要的是从头构建镜像的方法,所以重点应放在Dockerfile构建上,而不是手动修改容器。引用[3]提到Union文件系统和分层继承,说明镜像的分层结构,所以在步骤中需要强调每个指令都会生成一层,优化层数的重要性。 接下来,我需要整理步骤:安装Docker,创建Dockerfile,编写指令,构建镜像,验证。同时,示例Dockerfile以centos:7为基础,安装tomcat,符合引用[3]的例子。还要注意用户可能遇到的常见问题,比如权限问题需要sudo,或者Dockerfile的语法错误。 用户可能还想知道如何优化镜像大小,比如合并RUN指令,使用合适的基础镜像。此外,可能还需要解释docker build命令的-t参数和上下文路径的作用,避免文件找不到的问题。 最后,生成相关问题时要涵盖Dockerfile优化、多阶段构建、运行方法、与虚拟机区别和调试技巧,这些都是用户后续可能感兴趣的方面。</think>在Linux系统中创建和构建Docker镜像的步骤如下: ### 一、准备工作 1. 安装Docker引擎:使用`sudo apt-get install docker.io`(Ubuntu/Debian)或`sudo yum install docker`(CentOS)[^2] 2. 启动Docker服务:`sudo systemctl start docker` ### 二、创建Docker镜像 #### 方法1:通过Dockerfile构建(推荐) ```bash # 1. 创建项目目录 mkdir mydocker && cd mydocker # 2. 创建Dockerfile文件 cat <<EOF > Dockerfile # 指定基础镜像(分层继承的基础层)[^3] FROM centos:7 # 维护者信息(可选) LABEL maintainer="yourname@example.com" # 执行安装命令(每个RUN生成新镜像层) RUN yum install -y tomcat # 复制本地文件到镜像 COPY app.war /usr/local/tomcat/webapps/ # 暴露端口 EXPOSE 8080 # 容器启动命令 CMD ["catalina.sh", "run"] EOF # 3. 构建镜像(注意最后的.表示构建上下文) docker build -t my-tomcat-app:1.0 . ``` #### 方法2:通过容器修改提交(适合快速测试) ```bash # 1. 启动基础容器[^1] docker run -it centos:7 /bin/bash # 2. 在容器内进行修改(安装软件等) yum install -y tomcat exit # 3. 提交修改生成新镜像 docker commit <容器ID> my-custom-image ``` ### 三、验证镜像 ```bash # 查看镜像列表 docker images # 运行测试容器 docker run -d -p 8080:8080 my-tomcat-app:1.0 ``` ### 关键概念说明: 1. **分层构建**:每个Dockerfile指令都会生成只读层,优化指令顺序可减少镜像大小[^3] 2. **构建上下文**:`docker build`命令最后的`.`决定了文件访问范围 3. **缓存机制**:Docker会缓存已构建的层,修改Dockerfile后只会重建后续层
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值