目录

一、docker容器(Container)简介

1、什么是docker

2、传统虚拟化与docker的差别?

3、docker容器的优势

4、容器是如何工作的 

二、docker的安装

1、配置docker的软件源

2、安装docker-ce

3、启动docker

4、查看docker信息

5、docker中镜像的查询及下载

6、docker中镜像的使用

7、测试

三、docker的镜像

1、镜像的分层结构

2、镜像的构建——三部曲

(1)容器的创建(运行)与删除

(2)容器的更改

容器删除后重新启动,之前创建的文件没了。因此需要保存对容器的更改。

(3)镜像的删除

3、镜像的构建——Dockerfile文件

(1)编写Dockerfile文件

 (2)查看镜像

(3)镜像的缓存特性

4、Dockerfile详解

(1)Dockerfile官方文档:

(2)Dockerfile常用指令

(3)Dockerfile实践

5、镜像的优化

1、镜像的优化原则

2、优化实验一:减少镜像的层数,清理镜像构建的中间产物对构建的影响。

3、优化实验二:使用多阶段构建镜像

4、 优化实验三:选择最精简的基础镜像,使用多阶段构建镜像

四、docker命令的常用参数

五、本章总结



一、docker容器(Container)简介

1、什么是docker

 Docker就好比传统的货运集装箱

 Docker是管理容器的引擎。 Docker为应用打包、部署平台,而非单纯的虚拟化技术。

2、传统虚拟化与docker的差别?

3、docker容器的优势

对于开发人员:Build once、Run anywhere。

对于运维人员:Configure once、Run anything。

4、容器是如何工作的 

客户端——>Docker引擎——>仓库

二、docker的安装

1、配置docker的软件源

curl https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -o docker-ce.repo

修改软件docker软件源,只保留上一步中下载的第一个软件源路径,并取消校验。

这样配置的docker软件源没有解决依赖性,因此还需要进一步配置centos源20

wget https://mirrors.aliyun.com/repo/Centos-7.repo

对Centos-7.repo软件源做如下更改(其余部分删除)

软件源配置完成后,更新软件源列表,即可看到docker软件仓库和centos7的软件仓库。

2、安装docker-ce

yum install -y docker-ce

注意:这里有个小建议。在安装时可以把从外部下载的依赖包保存在自己的软件源中,再次安装时可以从自己的软件源中调取。否则每次都从网络上下载依赖包会比较麻烦。

解决办法:更改yum配置,保存缓存,那么在安装完软件后会将软件包保存在指定目录下。

3、启动docker

systemctl enable --now docker        #启动并设置docker开机自启动

4、查看docker信息

docker info            #查看docker信息

5、docker中镜像的查询及下载

docker search yakexi007                #查询容器
    NAME                      DESCRIPTION   STARS     OFFICIAL   AUTOMATED
    yakexi007/game2048                      0                    
    yakexi007/mario                         0                    
    yakexi007/nginx                         0                    
    yakexi007/base-debian10                 0                    
docker pull yakexi007/game2048          #拉取容器中的镜像
docker images                           #查看本地有哪些镜像
    

 

注意:docker的所有数据全部保存在目录</var/lib/docker/>中。

6、docker中镜像的使用

docker run -d --name demo -p 80:80 yakexi007/game2048        #运行镜像
     -d:打入后台; --name:项目名取为demo(加上名字后方便操作,不加时会随机创建一个名称);
     -p:端口映射(宿主机的80端口映射到docker的80端口)
docker ps                                                    #查看正在运行的镜像

7、测试

在浏览器中访问虚拟机IP,可以访问正在运行中的docker

三、docker的镜像

1、镜像的分层结构

共享宿主机的kernel;base镜像提供的是最小的Linux发行版;同一docker主机支持运行多种Linux发行版;采用分层结构的最大好处是:共享资源

Copy-on-Write 可写容器层;容器层以下所有镜像层都是只读的;docker从上往下依次查找文件;容器层保存镜像变化的部分,并不会对镜像本身进行任何修改;一个镜像最多127层。

2、镜像的构建——三部曲

Docker commit构建新镜像三部曲:

运行容器;修改容器;将容器保存为新的镜像(运行——>修改——>提交)

先拉取一个新镜像busybox

(1)容器的创建(运行)与删除

运行busybox镜像,镜像在运行时会占用终端,并且可以在shell中交互创建文件。<Ctrl>+<d>会退出容器进程

docker run -it --name demo busybox        #运行容器

重新启动容器,已经在后台运行,通过“attach”进入容器内部后,可以通过<Ctrl>+<p>+<q>将容器打入后台。

docker start demo         #启动容器
docker attach demo        #提取正在后台运行的容器

关闭容器,将会把后台运行的容器关闭,重新查看进程,确认demo容器已经不在后台运行。

docker stop demo         #关闭容器

(2)容器的更改

容器删除后重新启动,之前创建的文件没了。因此需要保存对容器的更改。

进入busybox容器内部,创建一个file1文件。退出后将更改提交(commit),并重新命名为“demo:v1”那么“demo:v1”就是在“busybox”的基础上新加了一层。通过docker history命令可以查看到两个容器的差别。

删除掉现有的容器demo,进入新的容器“demo:v1”后,可以看到之前的更改了。 

(3)镜像的删除

镜像的删除有两种方法,可以指定镜像名称,也可以指定镜像ID

docker rmi demo:v1                #指定镜像名称
docker rmi f4ac6fa47a2a            #指定镜像ID

此方法的缺点: 效率低、可重复性弱、容易出错;使用者无法对镜像进行审计,存在安全隐患

3、镜像的构建——Dockerfile文件

原理:Dockerfile文件中命令的每一层都是逐层提交的。即将构建的操作逻辑以文件的形式表现出来。

(1)编写Dockerfile文件

vim Dockerfile                            #编辑Dockerfile
    FROM busybox
    RUN touch file1
    Run echo westos > index.html
docker build -t demo:v1 .                 #构建Dockerfile
                    .表示构建的所有数据来自于当前目录

 (2)查看镜像

通过Dockerfile文件生成镜像后,如果只是要进入查看后退出,可以按照如下命令。

docker run  --rm -it demo:v1            #退出时删除容器

通过“docker history”可以看到Dockerfile文件中每一步的执行细节。退出容器后删除,再次查看进程已经查不到了。

(3)镜像的缓存特性

在上一个Dockerfile的最后再创建一个文件file2,构建时可以看到,前边几步在构建“demo:v1”时已经执行过了,所以构建“demo:v2”时不会再次执行,会使用上一次执行的缓存。 

4、Dockerfile详解

(1)Dockerfile官方文档:

Docker Documentation | Docker DocumentationHome page for Docker's documentationhttps://docs.docker.com/

(2)Dockerfile常用指令

FROM指定base镜像,如果本地不存在会从远程仓库下载。
MAINTAINER设置镜像的作者,比如用户邮箱等。
COPY

把文件从build context复制到镜像

支持两种形式:COPY src dest 和 COPY ["src", "dest"]

src必须指定build context中的文件或目录

ADD

用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:

ADD html.tar /var/www

ADD http://ip/html.tar /var/www

ENV

设置环境变量,变量可以被后续的指令使用:

ENV HOSTNAME sevrer1.example.com

EXPOSE

如果容器中运行应用服务,可以把服务端口暴露出去:

EXPOSE 80

VOLUME

申明数据卷,通常指定的是应用的数据挂在点:

VOLUME ["/var/www/html"]

WORKDIR为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。
RUN

在容器中运行命令并创建新的镜像层,常用于安装软件包:

RUN yum install -y vim

CMD 与 ENTRYPOINT

这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。

docker run后面的参数可以传递给ENTRYPOINT指令当作参数。

Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。

COPY指令:

注意:COPY指令执行时,目标文件只能用相对路径,不能用绝对路径。因此要处理的文件应该和Dockerfile文件放在同一目录下。

vim Dockerfile                         #编辑Dockerfile文件
    FROM busybox
    COPY index.html /                        #COPY命令
docker build -t demo:v1 .              #构建为demo:v1
docker history demo:v1                 #查看demo:v1的构建步骤
docker run --rm -it demo:v1            #仅查看容器demo:v1的执行结果

 

ADD指令:

此例中,由于所有指令都是基于第一步“FROM busybox”的镜像,如果busybox镜像中不含有该指令,那么将无法执行。对压缩文件来说,busybox中如果没有tar或者gzip命令,将无法处理压缩文件。因此引入“ADD”指令,执行后可以将压缩文件直接解压成目录。

注意:原文件可以来自本机,也可以来自网络

cat Dockerfile 
        FROM busybox
        COPY index.html /
        ADD nginx-1.20.2.tar.gz /
docker build -t demo:v2 .
docker history demo:v2
docker run --rm -it demo:v2                    #仅执行,不构建

ENV指令:

设置环境变量,变量可以被后续的指令使用

EXPOSE指令:

一般在docker中封装了一些服务,EXPOSE用于将这些服务的端口设置成对外开放。 

以超级玛丽游戏为例:

docker search yakexi007                    #查找镜像
        NAME                      DESCRIPTION   STARS     OFFICIAL   AUTOMATED
        yakexi007/game2048                      0                    
        yakexi007/mario                         0                    
        yakexi007/nginx                         0                    
        yakexi007/base-debian10                 0                    
        yakexi007/base-debian11                 0                    
docker pull yakexi007/mario                #拉取镜像
docker history yakexi007/mario:latest        #查看此镜像的详细信息
docker run -d --name demo -p 80:8080 yakexi007/mario      
                      #后台运行,并将镜像中的8080端口映射为宿主机的80端口

后台运行后,在浏览器访问宿主机的80时,实际上访问的是容器内的8080。可以看到正在运行的镜像。

 VOLUME指令:

申明数据卷,通常指定的是应用的数据挂载点。用于分离容器和数据的,可以是本地,也可以是远程。(相当于数据直接写入宿主机)

由于容器的文件系统是比较慢的,因此通过此方式,将容器中的文件直接挂载到宿主机中,和宿主机中的文件系统保持一致,可以加快文件读写速度。

cat Dockerfile 
        FROM busybox
        VOLUME /data            #创建卷
docker build -t demo:v3 .            #构建为demo:v3

docker history demo:v3
docker run -it --name demo1 demo:v3        #运行容器并命名为demo1

 运行容器后,在卷目录“/data”下新建文件file1,可以查看到卷中内容已发生改变。

docker inspect demo1        #查看demo1的详细信息

 表示宿主机中的这个目录实际上挂载的是容器中的“/data”目录下。

进入此目录下,可以看到之前在容器内创建的文件。且映射的这两个目录是同步的。在宿主机的此目录下创建file2,重新进土容器后,也可以在该卷中看到file2. 

VOLUME的删除:删除容器时,创建的卷不会一起删掉,因此需要单独删除

[root@server1 docker]# docker volume ls
        DRIVER    VOLUME NAME
        local     bdf969483abfb346f3f51ae50655cc4949fc521a5696a7ee043e9b59163c439a
[root@server1 docker]# docker volume rm bdf969483abfb346f3f51ae50655cc4949fc521a5696a7ee043e9b59163c439a

 WORKDIR指令:

为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。(一般用户切换路径)

RUN指令:

在容器中运行命令并创建新的镜像层,常用于安装软件包:

RUN yum install -y vim

CMD 与 ENTRYPOINT 指令:

cat Dockerfile 
        FROM busybox
        CMD echo "hello world"            #CMD指令
docker build -t demo:v4 .                #构建demo:v4
docker run --rm demo:v4                  #运行后删除(仅查看运行结果)
        hello world                        #运行结果

 CMD里可以写多个,但只有最后一个生效。

书写格式:一般有shell和exec两种书写格式。

Shell和exec格式的区别为:

ENTRYPOINT echo "hello, $name"

Shell格式底层会调用/bin/sh -c来执行命令,可以解析变量,而下面的exec格式不会:ENTRYPOINT ["/bin/echo", "hello, $name"]

需要改写成以下形式:ENTRYPOINT ["/bin/sh", "-c", "echo hello, $name"]

# cat Dockerfile
        FROM busybox
        CMD echo "hello world"                                #shell格式
        CMD echo "hello $hostname"                            #shell格式(解析变量)
        CMD ["/bin/sh", "-c", "echo hello $hostname"]         #exec格式

CMD 与 ENTRYPOINT 区别:

一般情况下,两个命令可以相互替换。区别在于,CMD可以被覆盖而ENTRYPOINT不能被覆盖。

已CMD命令结尾时,Dockerfile默认输出为“hello world”。先构建,再运行,在运行时、传入参数“linux”,这个参数将会覆盖原文件中的CMD命令“world”,输出变为“hello linux”。

[root@server1 docker]# cat Dockerfile             
        FROM busybox
        ENTRYPOINT ["/bin/echo", "hello"]
        CMD ["world"]
[root@server1 docker]# docker build -t demo:v1 .        #构建
[root@server1 docker]# docker run --rm demo:v1            #运行
        hello world
[root@server1 docker]# docker run --rm demo:v1 linux        #运行时传参
        hello linux

一般要进入某个容器而不运行时,可以在运行命令的最后加上“bash”,则会替换掉原本的CMD命令。

docker run --rm -it demo:v3            
docker run --rm -it demo:v3 bash

(3)Dockerfile实践

#Dockerfile文件内容
#vim Dockerfile                                               
  1 FROM centos:7
  2 ADD nginx-1.20.2.tar.gz /mnt
  3 WORKDIR "/mnt/nginx-1.20.2"
  4 RUN yum install -y gcc make pcre-devel zlib-devel
  5 RUN ./configure --prefix=/usr/local/nginx
  6 RUN make
  7 RUN make install
  8 EXPOSE 80
  9 VOLUME /usr/local/nginx/html
 10 CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
docker build -t demo:v1 .                    #构建
docker run -d --name demo demo:v1            #运行

[root@server1 docker]# docker ps                #查看是否运行
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
8b6a5b3e6579   demo:v1   "/usr/local/nginx/sb…"   6 seconds ago   Up 6 seconds   80/tcp    demo

[root@server1 docker]# docker inspect demo | grep IPAddress        #查看容器详细信息
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",


[root@server1 docker]# curl 172.17.0.2            #测试
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;

因为有卷VOLUME的存在,所以可以直接更改宿主机的发布目录。发布目录可以通过“docker inspect demo”查找到。更改发布文件后,再次访问nginx的IP,可以看到修改成功。 

5、镜像的优化

1、镜像的优化原则

选择最精简的基础镜像
减少镜像的层数
清理镜像构建的中间产物
注意优化网络请求
尽量去用构建缓存
使用多阶段构建镜像

2、优化实验一:减少镜像的层数,清理镜像构建的中间产物对构建的影响。

在上一步实验的基础上做如下更改:

#编辑Dockerfile文件
# vim Dockerfile 
  1 FROM centos:7
  2 ADD nginx-1.20.2.tar.gz /mnt
  3 WORKDIR "/mnt/nginx-1.20.2"
  4 RUN yum install -y gcc make pcre-devel zlib-devel && ./configure --prefix=/usr/local/nginx && make && make install && rm -fr /mnt/nginx-1.20.2
  5 EXPOSE 80
  6 VOLUME /usr/local/nginx/html
  7 CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

优化后的容器为demo:v2,和未优化的demo:v1相比,占用空间有所减少。

3、优化实验二:使用多阶段构建镜像

以下为例,第一阶段构建,构建完成后将产生的二进制文件直接复制到“/usr/local/nginx”目录下。

#编辑Dockerfile文件
#vim Dockerfile
  1 FROM centos:7 as build
  2 ADD nginx-1.20.2.tar.gz /mnt
  3 WORKDIR "/mnt/nginx-1.20.2"
  4 RUN yum install -y gcc make pcre-devel zlib-devel && ./configure --prefix=/usr/local/nginx && make && make install && rm -fr /mnt/nginx-1.20.2
  5 
  6 
  7 FROM centos:7
  8 COPY --from=build /usr/local/nginx /usr/local/nginx
  9 EXPOSE 80
 10 VOLUME /usr/local/nginx/html
 11 CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

 重新构建的镜像命名为“demo:v3”,占用空间进一步减小。

4、 优化实验三:选择最精简的基础镜像,使用多阶段构建镜像

注意:这里用到的nginx为1.18.0版本的,所以在执行前需要先拉取这个版本的nginx

<docker pull nginx:1.18.0>

#编辑Dockerfile文件
#vim Dockerfile

  1 FROM nginx:1.18.0 as base
  2 
  3 # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
  4 ARG TIME_ZONE
  5 
  6 RUN mkdir -p /opt/var/cache/nginx && \
  7     cp -a --parents /usr/lib/nginx /opt && \
  8     cp -a --parents /usr/share/nginx /opt && \
  9     cp -a --parents /var/log/nginx /opt && \
 10     cp -aL --parents /var/run /opt && \
 11     cp -a --parents /etc/nginx /opt && \
 12     cp -a --parents /etc/passwd /opt && \
 13     cp -a --parents /etc/group /opt && \
 14     cp -a --parents /usr/sbin/nginx /opt && \
 15     cp -a --parents /usr/sbin/nginx-debug /opt && \
 16     cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
 17     cp -a --parents /lib/x86_64-linux-gnu/libpcre.so.* /opt && \
 18     cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
 19     cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
 20     cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
 21     cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
 22     cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
 23     cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
 24     cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
 25     cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
 26 
 27 FROM gcr.io/distroless/base-debian10
 28 
 29 COPY --from=base /opt /
 30 
 31 EXPOSE 80 443
 32 
 33 ENTRYPOINT ["nginx", "-g", "daemon off;"]

 修改完Dockerfile文件后,构建为“demo:v4”后测试。可以看到此优化方法构建的镜像"demo:v4"占用空间已经大大减小。

docker build -t demo:v4 .                    #构建
docker run -d --name demo demo:v4            #启动


[root@server1 docker]# docker ps             #查看容器进程
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS             NAMES
715599f41644   demo:v4   "nginx -g 'daemon of…"   2 minutes ago   Up 2 minutes   80/tcp, 443/tcp   demo

 测试:可以正常访问nginx

四、docker命令的常用参数

docker search busybox(镜像名)查询镜像
docker pull busybox(镜像名)拉取镜像
docker images

显示所有镜像

docker ps显示后台运行的镜像
docker run -d --name demo -p 80:80 yakexi007/game2048(镜像名)     运行镜像
docker rm -f demo删除镜像
docker history  yakexi007/game2048(镜像名)查看镜像的构建历史
docker inspect yakexi007/game2048:latest(镜像名)查看镜像的具体信息
docker container prune删除已经退出的容器
docker load -i base-debian10.tar (镜像名)导入本地镜像
docker tag gcr.io/distroless/base-debian10 zzh981030/base-debian10:latest重新给镜像打标签

五、本章总结

1、在安装好docker后,查看docker信息。显示docker的网桥连接有问题,这是因为火墙权限引起的。

解决办法:手动设置网桥选项

#编辑system配置文件
[root@server2 ~]# vim /etc/sysctl.d/docker.conf

#system内容如下
[root@server2 ~]# cat /etc/sysctl.d/docker.conf
    net.bridge.bridge-nf-call-iptables = 1
    net.bridge.bridge-nf-call-ip6tables = 1

#重新载入system配置,使之生效
[root@server2 ~]# sysctl --system
    net.bridge.bridge-nf-call-iptables = 1
    net.bridge.bridge-nf-call-ip6tables = 1

再次查看,已没有此报错

2、导入本地镜像包

docker load -i base-debian10.tar (镜像名)

3、打包镜像到本地

docker save -o busybox:1.27.tar busybox:1.27(镜像名)

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐