简介
docker 镜像只能在表层附加层进行修改
层级分布:最多127层
资源共享
常用指令:
docker run -it --name demo test:v1
run #运行一个容器
-i #保持容器以交互模式运行
-t #为容器重新分配一个伪输入终端
-d #打入后台
–name #命名
-P #随机端口映射,容器内部端口随机映射到主机的高端口
-p #作端口映射
-v #绑定一个卷
docker exec -it redis容器 bash #进入后台运行容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
docker run -it --name Busybox(名字) busybox(镜像)
将本地的 80 端口映射到容器的 80 端口,可以执行如下命令:
docker run -p 80:80 -v /data:/data -d nginx:latest
docker rmi #删除镜像
docker commit
docker ps
history
docker rmi testbox:latest #删除testbox:latest镜像
docker ps #查看正在运行的镜像
docker ps -a #查看所有镜像(运行、没运行)
##退出交互式的方式
ctrl+ d 退出并关闭容器
ctrl+ pq 退出并将容器打入后台
删除运行容器:
docker stop 容器名
docker rm 容器名
dockerfile
Dockerfile详解
FROM
指定base镜像,如果本地不存在则从网络拉取
MAINTAINER
设置镜像的作者,比如用户邮箱等等
Copy
从本机将文件从build context复制到镜像
支持两种形式: COPY src dest和COPY [“src”, “dest”]
需要注意的是本机文件必须位于build context, 也就是Dockerfile所在目录中
ADD
用法与COPY类似,不同的是src可以是归档压缩文件,文件会被解压后放入容器内
本机文件并不需要位于build context中
也可以从网络下载文件并拷贝到镜像
ENV
设置环境变量,变量可以被后续的指令使用
举例 ENV HOSTNAME Server1.example.com
EXPOSE
如果在容器中运行应用服务,需要把服务端口暴露出去的时候使用
EXPOSE 80, 即对外暴露80端口
VOLUME
申明数据卷, 通常指定的是应用的数据挂载点
挂载目录的目的是为了持久化
举例 VOLUME ["/var/www/html"]
WORKDIR
为RUN, CMD, ENTERPOINT, ADD, COPY指令设置镜像中的当前工作目录
如果目录不存在则会自动创建
RUN
在容器中运行命令并创建新的镜像层, 常用于安装软件包
举例 RUN yum install -y vim
CMD和ENTRYPOINT
这两个指定都是用于设置容器启动后执行的命令
区别在于CMD会被RUN后面的命令行覆盖, 而ENTRYPOINT一定不会被忽略/一定会执行
docker run后面的参数可以传递给ENTRYPOINT指令作为参数
Dockerfile中只能指定一个ENTRYPOINT, 如果指定了很多个则只有最后一个有效
FROM busybox
RUN mkdir Test
RUN touch /Test/Testfile
COPY index.html /
ADD nginx-1.18.0.tar.gz /
RUN mv nginx-1.18.0 Nginx
ENV HOSTNAME Server1
EXPOSE 80
VOLUME ["/data"]
WORKDIR /Test
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]
Sending build context to Docker daemon 1.043MB
Step 1/12 : FROM busybox
---> 388056c9a683
Step 2/12 : RUN mkdir Test
---> Running in 939e77e989f6
Removing intermediate container 939e77e989f6
---> 9537fc624d09
Step 3/12 : RUN touch /Test/Testfile
---> Running in 2ce46791eec2
Removing intermediate container 2ce46791eec2
---> 169b8b8c81f7
Step 4/12 : COPY index.html /
---> 6abd12f14c62
Step 5/12 : ADD nginx-1.18.0.tar.gz /
---> 7fd946b03383
Step 6/12 : RUN mv nginx-1.18.0 Nginx
---> Running in 9ac35e723827
Removing intermediate container 9ac35e723827
---> a817a5a3b1eb
Step 7/12 : ENV HOSTNAME Server1
---> Running in 5a494de50eb1
Removing intermediate container 5a494de50eb1
---> eb900f03448c
Step 8/12 : EXPOSE 80
---> Running in 77affb4662d8
Removing intermediate container 77affb4662d8
---> e17a7d084fcb
Step 9/12 : VOLUME ["/data"]
---> Running in 4208622c722a
Removing intermediate container 4208622c722a
---> 281920256f8d
Step 10/12 : WORKDIR /Test
---> Running in 31f5db039dd2
Removing intermediate container 31f5db039dd2
---> 73b41cdf5a3c
Step 11/12 : ENTRYPOINT ["/bin/echo", "hello"]
---> Running in bb798ebc3335
Removing intermediate container bb798ebc3335
---> bb598d50bedf
Step 12/12 : CMD ["world"]
---> Running in 3ac90fc7965b
Removing intermediate container 3ac90fc7965b
---> bae4405b5d28
Successfully built bae4405b5d28
Successfully tagged demo:latest
docker run --rm demo:latest #–rm参数常用于临时测试内容,当命令执行结束后临时生成的容器就会关闭并删除,在其后跟着的参数会传递给容器使用
[root@Server1 Docker]# docker run --rm demo:latest
hello world
[root@Server1 Docker]# docker run --rm demo:latest linux
hello linux
docker inspect # 用于获取容器/镜像的元数据,其中 -f 参数可以用于获取指定的数据,例如使用 docker inspect -f {{.IPAddress}} 来获取容器的 IP 地址。
镜像的优化
优化逻辑
选择最精简的基础镜像
减少镜像的层数
清理镜像构建的中间产物
注意优化网络请求
尽量去用构建缓存
使用多阶段构建镜像
举例
首先尝试创建一个Nginx的镜像,这里使用精简版的RHEL7作为base镜像
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY NeuWings.repo /etc/yum.repos.d/NeuWings.repo
RUN rm -rf /etc/yum.repos.d/rhel7.repo
RUN rpmdb --rebuilddb
RUN yum install -y gcc pcre-devel zlib-devel > /dev/null
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN ./configure --prefix=/usr/local/nginx > /dev/null
RUN yum install -y make > /dev/null
RUN make > /dev/null
RUN make install > /dev/null
CMD ["/usr/local/nginx/sbin/nginx", "-g" "daemon off;"]
查看构建完成的大小: 346M
尝试精简
压缩镜像的层数,将可以放在同一条命令执行的都整合到同一条
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY NeuWings.repo /etc/yum.repos.d/NeuWings.repo
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN rm -rf /etc/yum.repos.d/rhel7.repo && rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make > /dev/null && /mnt/nginx-1.18.0/configure --prefix=/usr/local/nginx > /dev/null && yum install -y make > /dev/null && make > /dev/null && make install > /dev/null && yum clean all > /dev/null && rm -rf /mnt/nginx-1.18.0
查看构建完成的大小: 258M
已知其实我们需要的其实只是Nginx的二进制文件, 中途为了编译而安装的依赖以及编译中产生的内容其实在服务中都没有用到
采用多阶段构建的方法,创建一个临时镜像用于编译,将编译好的二进制文件拷贝到最终要创建的镜像
FROM rhel7 as build
COPY NeuWings.repo /etc/yum.repos.d/NeuWings.repo
ADD nginx-1.18.0.tar.gz /mnt
RUN rm -rf /etc/yum.repos.d/rhel7.repo && rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make > /dev/null && cd /mnt/nginx-1.18.0 && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx > /dev/null && yum install -y make > /dev/null && make > /dev/null && make install > /dev/null && yum clean all > /dev/null && rm -rf /mnt/nginx-1.18.0 && rm -rf /var/cache/yum
FROM rhel7
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g" "daemon off;"]
首先构建一个镜像,镜像内编译安装Nginx
再阶段性构建第二个镜像,将第一个镜像中的Nginx二进制文件复制过来
这种方式省去了中途安装的依赖和编译内容,镜像大小大大降低
[root@Server1 Docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo2 latest 94f2bf6f8c66 7 seconds ago 141MB
<none> <none> 56fe29ab9d19 8 seconds ago 258MB
demo latest 181d43b6a7dc 24 minutes ago 346MB
rhel7 latest 0a3eb3fde7fd 6 years ago 140MB
查看构建完成的大小: 141M, 仅比base镜像大了1m而已.
如果还要继续压缩,就只能寻找更精简的base镜像了
FROM nginx as base
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG TIME_ZONE
RUN mkdir -p /opt/var/cache/nginx && \
cp -a --parents /usr/lib/nginx /opt && \
cp -a --parents /usr/share/nginx /opt && \
cp -a --parents /var/log/nginx /opt && \
cp -aL --parents /var/run /opt && \
cp -a --parents /etc/nginx /opt && \
cp -a --parents /etc/passwd /opt && \
cp -a --parents /etc/group /opt && \
cp -a --parents /usr/sbin/nginx /opt && \
cp -a --parents /usr/sbin/nginx-debug /opt && \
cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpcre.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
FROM gcr.io/distroless/base-debian10
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]
##获取最精简的基础镜像
[root@Server1 Docker]# docker load < base-debian10.tar
de1602ca36c9: Loading layer 3.041MB/3.041MB
1d3b68b6972f: Loading layer 17.77MB/17.77MB
Loaded image: gcr.io/distroless/base-debian10:latest
##构建需要的nginx镜像
[root@Server1 Docker]# docker build -t webserer:V1 -f Dockerfile2 .
##查看构建结果
[root@Server1 Docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
webserer V1 059742ab983d 6 seconds ago 31.9MB
<none> <none> 2cb570a37c5b 8 seconds ago 146MB
nginx latest 62d49f9bab67 13 days ago 133MB
gcr.io/distroless/base-debian10 latest d48fcdd54946 51 years ago 19.2MB
查看构建完成的大小: 31.9M