Docker容器技术

一、Docker简介及部署方法

1.1、Docker简介

Docker之父Solomon Hykes:Docker就好比传统的货运集装箱

1.1.1、什么是docker?

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

它具有以下几个重要特点和优势:

  • 轻量级虚拟化:
  • 一致性
  • 可移植性
  • 高效的资源利用
  • 易于部署和扩展

1.1.2、docker在企业中的应用场景

  • 在企业中docker作为业务的最小载体而被广泛应用
  • 通过docker企业可以更效率的部署应用并更节省资源

1.1.3、docker与虚拟化的对比

虚拟机Docker容器
操作系统宿主机上运行虚拟机OS共享宿主机OS
存储镜像较大(GB)镜像小(MB)
性能操作系统额外的cpu、内存消耗几乎无性能损耗
移植性笨重、与虚拟化技术耦合度高轻量、灵活迁移
隔离性完全隔离安全隔离
部署慢、分钟级快速、秒级
运行密度运行密度单机支持上千容器

1.1.4、docker的优势

  • 对于开发人员:Build once、Run anywhere。
  • 对于运维人员:Configure once、Run anything
  • 容器技术大大提升了IT人员的幸福指数!

1.2、部署docker

官方站点:https://docs.docker.com/ 

1.2.1、容器工作方法

1.2.2、部署第一个容器

1.2.2.1、软件源安装

1、​​​​​​​配置软件仓库

rhel9里面配置

只用添加Docker下载网址,因为rhel9里面依赖性自带 ​​​​​​​​​​​​​

[root@docker-node1 ~]# cd /etc/yum.repos.d/
[root@docker-node1 yum.repos.d]# vim docker.repo

[docker]

name=docker-ce

baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/rhel/9/x86_64/stable/

gpgcheck=0

在rhel7里面配置

[root@docker-node1 ~]# cd /etc/yum.repos.d

[root@docker-node1 ~]# vim docker.repo

[docker]

name=docker-ce

baseurl=https://mirrors.tuna.tsinghua.edu.cn/dockerce/linux/centos/7/x86_64/stable/

gpgcheck=0

[centos]

name=extras

baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/7/extras/x86_64

gpgcheck=0 

2、安装docker-ce并启动服务 

#安装docker

[root@docker-node1 ~]# yum install -y docker-ce

#编辑docker启动文件,设定其使用iptables的网络设定方式,默认使用nftables [root@docker-node1 ~]# vim /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true

[root@docker-node1 ~]# systemctl enable --now docker

[root@docker-node1 ~]# docker info 

3、激活内核网络选项

#在rhel7中 需要

[root@docker-node1 ~]# vim /etc/sysctl.d/docker.conf

net.bridge.bridge-nf-call-iptables = 1

net.bridge.bridge-nf-call-ip6tables = 1

net.ipv4.ip_forward = 1

[root@docker-node1 ~]# sysctl --system

[root@docker-node1 ~]# systemctl restart docker 

1.2.2.2、安装包安装

上传docker安装包 

[root@docker-node1 ~]# tar zxf docker.tar.gz

[root@docker-node1 ~]# ls

[root@docker-node1 ~]# yum install *.rpm -y

[root@docker-node1 ~]# systemctl enable --now docker 

二、Docker的基础操作

2.1、Docker镜像管理

1、搜索镜像

 [root@docker-node1 ~]# docker search nginx

  • name:镜像的名称
  • DISCRIPTION:镜像说明
  • START:点赞数量
  • OFFICAL:是否是官方的

2、拉取镜像

从镜像仓库中拉取

 [root@docker-node1 ~]# docker pull busybox

查看本地镜像

 [root@docker-node1 ~]# docker images

3、查看镜像的详细信息

 [root@docker-node1 ~]# docker image inspect nginx:latest

4、导出镜像

  • -o:指定导出镜像的位置
  • 可以同时导出多个镜像到一个文件中 
  • 指定.tar.gz 可以导出并压缩

#保存镜像

[root@docker-node1 ~]# docker image save nginx:latest -o nginx-latest.tar.gz

#保存所有镜像

[root@docker-node1 ~]# docker save `docker images | awk 'NR>1{print $1":"$2}'` - o images.tar.gz

5、删除镜像

删除指定一个

[root@Docker-node1 ~]# docker rmi nginx:latest

删除全部镜像

[root@Docker-node1 ~]# docker rmi `docker images | awk 'NR>1{print $1":"$2}'` 

2.2、容器常规操作 

  • -d:后台运行
  • -i:交互式运行
  • -t:打开一个终端
  • --name:指定容器名称
  • -p:端口映射 -p 80:8080 把容器8080端口映射到本机80端口
  • --rm:容器停止自动删除容器
  • --network:指定容器使用的网络 

1、启动容器 

[root@Docker-node1 ~]# docker run -d --name mario -p 80:8080 timinglee/mario [root@Docker-node1 ~]# docker run -it --name centos7 centos:7

[root@3ba22e59734f /]# #进入到容器中,按+退出并停止容器,#按+退出但 不停止容器

2、重新进入容器

 [root@docker ~]# docker attach centos7

3、在容器中执行命令 

[root@docker ~]# docker exec -it         test                 ifconfig

                                                            容器名               命令

三、docker镜像构建

 3.1、docker镜像结构

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

3.2、镜像运行的基本原理

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

3.3、镜像获得方式

  • 基本镜像通常由软件官方提供
  • 企业镜像可以用官方镜像+Dockerfile来生成
  • 系统关于镜像的获取动作有两种:
    • docker pull 镜像地址
    • docker load –i 本地镜像包

3.4、镜像构建

3.4.1、构建参数

1、FROM

指定base镜像 

2、MAINTAINER

指定作者信息,比如邮箱 eg:MAINTAINER user@example.com

在最新版的docker中用LABEL KEY="VALUE"代替

3、ENV

指定环境变量 

4、EXPOSE

暴漏容器端口

5、COPY

复制文件 eg:COPY file /file 或者 COPY [“file”,”/”]

6、ADD

功能和copy相似,指定压缩文件或url 

  • 解压压缩文件并把它们添加到镜像中
  • 从 url 拷贝文件到镜像中

7、VOLUME

申明数据卷,通常指数据挂载点

8、WORKDIR

切换路径

9、RUN

在容器中运行的指令

10、CMD

在启动容器时自动运行动作可以被覆盖

11、ENTRYPOINT

和CMD功能和用法类似,但动作不可被覆盖

示例:

[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# ls
Dockerfile

这里是随便建的一个haha的文件夹和复制过来的压缩包

[root@docker-node1 docker]# mkdir -p /haha/xixixi

[root@docker-node1 docker]# ls
Dockerfile  haha  images.tar.gz
[root@docker-node1 docker]# vim Dockerfile

FROM busybox:latest
RUN touch /zpyfile
LABEL Mail=zpy@timing.org
COPY haha /hahaha
ADD images.tar.gz /mnt
RUN mkdir /zpy
EXPOSE 80,443
ENV name=zpy
CMD ["/bin/bash","-c","echo $name"]
ENTRYPOINT ["/bin/sh","-c","echo end"]
[root@docker-node1 docker]# docker build -t busybox:v1 .

测试:

1、ENTRYPOINT和CMD,RUN

因为ENTRYPOINT不可被覆盖,COPY会被覆盖,就算他们两都写了,但最后还是执行的ENTRYPOINT,所以就算另加shell调用也不会被覆盖

如果把这条去除

2、ADD和COPY 

3、 LABEL

[root@docker-node1 ~]# docker image inspect busybox:v1

4、EXPOSE

查看容器运行的详细情况

[root@docker-node1 ~]# docker inspect test

3.4.2、Dockerfile实例

3.4.2.1、建立构建目录,编写构建文件

[root@docker-node1 ~]# cd docker/

[root@docker-node1 docker]# vim Dockerfile
[root@docker-node1 docker]# cat Dockerfile
FROM centos:repo
LABEL Mail=zpy@timingzpy.org
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install gcc make pcre-devel openssl-devel -y
RUN ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module
RUN make
RUN make install
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off"]

这里面ADD的nginx-1.26.1.tar.gz,需要我们自己上传到/root/docker/目录下

3.4.2.2、通过dockerfile生成镜像

因为我是想基于rhel7.9的版本做

所以我先去弄了个7.9的镜像

[root@docker-node1 ~]# docker load -i centos-7.tar.gz
174f56854903: Loading layer  211.7MB/211.7MB
Loaded image: centos:7

又因为我基于centos:7,没有网,所以我下载不了模块

所以我要基于这个镜像创的容器改一下

因为需要给它一个软件源

所以我通过在本机上安装一个httpd协议来传输

[root@docker-node1 ~]# yum install httpd -y

改一下端口,除了80,都可以,因为nginx要用80端口
[root@docker-node1 ~]# vim /etc/httpd/conf/httpd.conf
[root@docker-node1 ~]# systemctl enable --now httpd

我们将添加的7.9镜像的光盘挂载到web默认根目录下
[root@docker-node1 ~]# mkdir /var/www/html/rhel7.9
[root@docker-node1 ~]# mount /dev/sr1 /var/www/html/rhel7.9/
mount: /var/www/html/rhel7.9: WARNING: source write-protected, mounted read-only.

这样就可以通过链接下载软件了

后我们就可以配制容器了
[root@docker-node1 ~]# docker run -it --name centos centos:7
[root@e4f70c1add6a /]# cd /etc/yum.repos.d/

[root@e4f70c1add6a yum.repos.d]# ls
CentOS-Base.repo       CentOS-Media.repo    CentOS-fasttrack.repo
CentOS-CR.repo         CentOS-Sources.repo  CentOS-x86_64-kernel.repo
CentOS-Debuginfo.repo  CentOS-Vault.repo
[root@e4f70c1add6a yum.repos.d]# rm -rf *
[root@e4f70c1add6a yum.repos.d]# ls
[root@e4f70c1add6a yum.repos.d]# vi centos7.repo
[centos]

name=centos

baseurl=http://172.25.254.100:8080/rhel7.9

gpgcheck=0

配置完后,先重新开一个会话一下,将这个容器提交一下,生成另一个容器

[root@docker-node1 ~]# docker commit -m "add repo" centos centos:repo

然后就可以退出
[root@e4f70c1add6a ~]# exit

这个容器就可以删除了

[root@docker-node1 ~]# docker rm centos
最后就可以通过dockerfile生成镜像了
 [root@server1 docker]# docker build -t webserver:v1 .

3.4.2.3、测试镜像可用性

[root@docker-node1 docker]# docker history webserver:v1
[root@docker-node1 docker]# docker run -d --name checkimage webserver:v1
63b534528bed6c212c27fbc1bbc4b4cd6f33f3d64b08260412fcfee6767c1608

3.4.2.4、查看容器详情

docker inspect webserver:v1

3.5、镜像优化方案

3.5.1、镜像优化策略

  • 选择最精简的基础镜像
  • 减少镜像的层数
  • 清理镜像构建的中间产物
  • 选择最精简的基础镜像
  • 减少镜像的层数
  • 减少镜像的层数

3.5.2、镜像优化示例

3.5.2.1、缩减镜像层

[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# vim Dockerfile

FROM centos:repo
LABEL Mail=zpy@timingzpy.org
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install gcc make pcre-devel openssl-devel -y && ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module && make && make install && rm -rf /mnt/nginx-1.26.1 && yum clean all
EXPOSE 80 443
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
 

生成镜像

[root@docker-node1 docker]# docker build -t webserver2:v2 .

3.5.2.2、多阶段构建

[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# vim Dockerfile

FROM centos:repo AS build
ADD nginx-1.26.1.tar.gz /mnt
WORKDIR /mnt/nginx-1.26.1
RUN yum install gcc make pcre-devel openssl-devel -y && ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module && make && make install && rm -rf /mnt/nginx-1.26.1 && yum clean all

FROM centos:repo
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;"]

3.5.2.3、使用最精简镜像

下载地址: https://github.com/GoogleContainerTools/distroless 

下载镜像:

docker pull gcr.io/distroless/base

利用最精简镜像构建

[root@docker-node1 ~]# docker load -i debian11.tar.gz

我们可以进入一个nginx容器里看看,nginx真正安装必须调用的模块

 [root@docker-node1 ~]# docker run -it --name webserver webserver:v1 sh
sh-4.2# ldd /usr/local/nginx/sbin/nginx
        linux-vdso.so.1 =>  (0x00007ffed9ae5000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f9e81020000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f9e80e04000)
        libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f9e80bcd000)
        libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f9e8096b000)
        libssl.so.10 => /lib64/libssl.so.10 (0x00007f9e806f9000)
        libcrypto.so.10 => /lib64/libcrypto.so.10 (0x00007f9e80296000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f9e80080000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f9e7fcb2000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9e81224000)
        libfreebl3.so => /lib64/libfreebl3.so (0x00007f9e7faaf000)
        libgssapi_krb5.so.2 => /lib64/libgssapi_krb5.so.2 (0x00007f9e7f862000)
        libkrb5.so.3 => /lib64/libkrb5.so.3 (0x00007f9e7f579000)
        libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007f9e7f375000)
        libk5crypto.so.3 => /lib64/libk5crypto.so.3 (0x00007f9e7f142000)
        libkrb5support.so.0 => /lib64/libkrb5support.so.0 (0x00007f9e7ef32000)
        libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f9e7ed2e000)
        libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f9e7eb14000)
        libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f9e7e8ed000)
sh-4.2#

然后讲这些模块放到我们我们的Dockerfile文件里

[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# vim Dockerfile

FROM nginx:1.23 AS base
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 /usr/lib/x86_64-linux-gnu/libpcre* /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-debian11
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]

生成镜像

[root@docker-node1 docker]# docker build -t webserver4:v4 .

现在已经与最简安装接近了

四、Docker镜像仓库的管理

4.1、docker仓库介绍

  • Docker 仓库(Docker Registry) 是用于存储和分发 Docker 镜像的集中式存储库。

  • 我们可以从中拉取镜像,也可以上传镜像

  • Docker仓库有公有仓库和私有仓库

4.2、Docker hub—公有仓库

官网:https://hub.docker.com/

  • Docker Hub 是 Docker 官方提供的一个公共的镜像仓库服务。
  • 它是 Docker 生态系统中最知名和广泛使用的镜像仓库之一,拥有大量的官方和社区贡献的镜像。

4.2.1、docker hub的使用方法

4.3、docker仓库的工作原理

仓库中的三个角色

  • index docker索引服务,负责并维护有关用户帐户、镜像的校验以及公共命名空间的信息。
  • registry docker仓库,是镜像和图表的仓库,它不具有本地数据库以及不提供用户认证,通过Index Auth service的Token的方式进行认证
  • Registry Client Docker充当registry客户端来维护推送和拉取,以及客户端的授权。

4.3.1、pull原理

1.docker客户端向index发送镜像拉曲请求并完成与index的认证

2.index发送认证token和镜像位置给dockerclient

3.dockerclient携带token和根据index指引的镜像位置去连接registry

4.Registry会根据client持有的token跟index核实身份合法性

5.index确认此token合法性

6.Registry会根据client的请求传递镜像到客户端

4.3.2、push原理

 

1.client向index发送上传请求并完成用户认证

2.index会发方token给client来证明client的合法性

3.client携带index提供的token连接Registry

4.Registry向index合适token的合法性

5.index证实token的合法性

6.Registry开始接收客户端上传过来的镜像

4.4、创建私有仓库

4.4.1、为什么搭建私有仓库  

  • 因为公有的需要internet连接,速度慢,且所有人都可登录,上传镜像安全性没有保证。
  • 好消息是docker公司已经将registry开源,我们可以快速构建企业私有仓库
  • 地址: https://docs.docker.com/registry/deploying/

 4.4.2、搭建简单的Registry仓库

直接下载镜像

[root@docker-node1 ~]# docker pull registry

或导入镜像

[root@docker-node1 ~]# docker load -i registry.tag.gz

开启registry
[root@docker-node1 ~]# docker run -d -p 5000:5000 --restart=always --name registry

上传镜像到仓库

#给要上传的经镜像大标签

[root@docker-node1 ~]# docker tag webserver4:v4 172.25.254.100:5000/webserver4:v4

上传

[root@docker-node1 ~]# docker push 172.25.254.100:5000/webserver4:v4
The push refers to repository [172.25.254.100:5000/webserver4]
Get "https://172.25.254.100:5000/v2/": http: server gave HTTP response to HTTPS client

因为它默认用HTTPS,所以我们需要做认证

或配置非加密端口

[root@docker-node1 ~]# vim /etc/docker/daemon.json

{
  "insecure-registries" : ["http://172.25.254.100:5000"]
}
[root@docker-node1 ~]# systemctl start docker.service

再次上传

[root@docker-node1 ~]# docker push 172.25.254.100:5000/webserver4:v4

推去的数据在哪里呢

[root@docker-node1 ~]# docker inspect registry:latest

#查看镜像上传

[root@docker-node1 ~]# curl 172.25.254.100:5000/v2/_catalog

4.4.3 为Registry提加密传输

做解析

[root@docker-node1 ~]# mkdir certs
[root@docker-node1 ~]# vim /etc/hosts

生成认证key和证书
[root@docker-node1 ~]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/timingzpy.org.key -addext "subjectAltName = DNS:reg.timingzpy.org" -x509 -days 365 -out certs/timingzpy.org.crt

启动register仓库

[root@docker-node1 ~]# docker run -d -p 443:443 --restart=always -v /root/certs:/certs -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timingzpy.org.crt  -e REGISTRY_HTTP_TLS_KEY=/certs/timingzpy.org.key registry:latest

# docker run -d -p 443:443 --restart=always --name registry \ > --name registry -v /opt/registry:/var/lib/registry \ > -v /root/certs:/certs \ > -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \ > -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timinglee.org.crt \ > -e REGISTRY_HTTP_TLS_KEY=/certs/timinglee.org.key registry

测试:上传

[root@docker-node1 ~]# docker tag webserver4:v4 registry.timingzpy.org/nginx:last

#为客户端建立证书
[root@docker-node1 ~]# mkdir -p /etc/docker/certs.d/registry.timingzpy.org    

[root@docker-node1 ~]# cp /root/certs/timingzpy.org.crt /etc/docker/certs.d/register.timingzpy.org/ca.crt
[root@docker-node1 ~]# systemctl restart docker
[root@docker-node1 ~]# docker push registry.timingzpy.org/nginx:last
[root@docker docker]# curl -k https://registry.timingzpy.org/v2/_catalog

4.4.4 为仓库建立登陆认证

#安装建立认证文件的工具包

[root@docker-node1 ~]# dnf install httpd-tools -y

#建立认证文件,我的密码都是123

[root@docker-node1 ~]# mkdir auth

#-B 强制使用最安全加密方式, 默认用md5加密
[root@docker-node1 ~]# htpasswd -Bc auth/.htpasswd zpy
[root@docker-node1 ~]# htpasswd -B auth/.htpasswd admin
New password:
Re-type new password:
Adding password for user admin
[root@docker-node1 ~]# cat auth/.htpasswd
zpy:$2y$05$I2EQ4obgsDLGmUXSh8x0GuAHDcWQqBtohKQPnGtOWs/g3.k6f5bza
admin:$2y$05$uAxefw3Yb1zLzrZjGZI5hOW03zpodpu0Ou26Q0v/f.aKF5DQxnwbK

#添加认证到registry容器中

[root@docker-node1 ~]# docker run -d -p 443:443 --restart=always -v /root/certs:/certs -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timingzpy.org.crt -e REGISTRY_HTTP_TLS_KEY=/certs/timingzpy.org.key -v /root/auth:/auth -e REGISTRY_AUTH=htpasswd -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/.htpasswd registry
 

测试:

上传镜像

[root@docker-node1 ~]# docker tag nginx:latest registry.timingzpy.org/nginx:latest

#未登陆情况下上传镜像
[root@docker-node1 ~]# docker push registry.timingzpy.org/nginx:latest
The push refers to repository [registry.timingzpy.org/nginx]
5f0272c6e96d: Preparing
f4f00eaedec7: Preparing
55e54df86207: Preparing
ec1a2ca4ac87: Preparing
8b87c0c66524: Preparing
72db5db515fd: Preparing
9853575bc4f9: Preparing
no basic auth credentials

#登录认证后,才能上传

[root@docker-node1 ~]# docker login reg.timingzpy.org
Username: zpy
Password:123
[root@docker-node1 ~]# docker push registry.timingzpy.org/nginx:latest
The push refers to repository [registry.timingzpy.org/nginx]
5f0272c6e96d: Pushed
f4f00eaedec7: Pushed
55e54df86207: Pushed
ec1a2ca4ac87: Pushed
8b87c0c66524: Pushed
72db5db515fd: Pushed
9853575bc4f9: Pushed
latest: digest: sha256:127262f8c4c716652d0e7863bba3b8c45bc9214a57d13786c854272102f7c945 size: 1778
#查看上传镜像

[root@docker-node1 ~]# curl -k https://172.25.254.100/v2/_catalog
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"registry","Class":"","Name":"catalog","Action":"*"}]}]}

-u:是添加认证,不然看不了
[root@docker-node1 ~]# curl -k https://172.25.254.100/v2/_catalog -uzpy:123
{"repositories":["nginx"]}

4.5、构建企业级私有仓库

下载软件包地址 https://github.com/goharbor/harbor/releases

Harbor 是由vmware公司开源的企业级 Docker Registry 项目。

4.5.1、部署harbor

前提先安装完docker

后部署harbor

上传后解压

tar zxf harbor-offline-installer-v2.5.4.tgz
[root@hub ~]# cd harbor

[root@hub harbor]# cp harbor.yml.tmpl harbor.yml
[root@hub harbor]# ls
common     docker-compose.yml    harbor.yml       install.sh  prepare
common.sh  harbor.v2.5.4.tar.gz  harbor.yml.tmpl  LICENSE
[root@hub harbor]# vim harbor.yml

更改为自己的域名

更改认证证书的位置

这个改成自己想要的密码

需要做域名解析

 生成认证key和证书

[root@hub harbor]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/timingzpy.org.key -addext "subjectAltName = DNS:reg.timingzpy.org" -x509 -days 365 -out certs/timingzpy.org.crt

[root@hub harbor]# cp /root/certs/ /data/ -r

[root@docker harbor]#  vim /etc/docker/daemon.json
{
  "registry-mirrors": ["https://reg.timingzpy.org"]
}

[root@docker harbor]# ./install.sh --help

Please set --with-notary #证书签名

Please set --with-trivy #安全扫描

Please set --with-chartmuseum if needs enable Chartmuseum in Harbor

[root@hub harbor]# ./install.sh --with-chartmuseum

这样下载好就可以了

五、Docker网络

5.1、docker原生bridge网路

docker安装时会创建一个名为 docker0 的Linux bridge,新建的容器会自动桥接到这个接口

[root@docker ~]# ip link show type bridge
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
    link/ether 02:42:73:b2:4b:24 brd ff:ff:ff:ff:ff:ff

  • bridge模式下容器没有一个公有ip,只有宿主机可以直接访问,外部主机是不可见的。
  •  容器通过宿主机的NAT规则后可以访问外网

创建容器

[root@docker ~]# docker run -it --name webserver --network bridge busybox:latest

使其可以使用网络

[root@docker ~]# ifconfig

5.2、docker原生网络host

  • host网络模式需要在容器创建时指定 --network=host
  • host模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性
  • 如果公用一个网络,那么所有的网络资源都是公用的,比如启动了nginx容器那么真实主机的80端口被占 用,在启动第二个nginx容器就会失败

[root@docker ~]# docker run -it --name test --network host busybox

5.3、docker 原生网络none

  • none模式是指禁用网络功能,只有lo接口,在容器创建时使用 --network=none指定。 

 [root@docker ~]# docker run -it --name test --rm --network none busybox

5.4、docker的自定义网络

  • 自定义网络模式,docker提供了三种自定义网络驱动:
    • bridge
    • overlay
    • macvlan 
  • bridge驱动类似默认的bridge网络模式,但增加了一些新的功能
  • overlay和macvlan是用于创建跨主机网络
  • 建议使用自定义的网络来控制哪些容器可以相互通信,还可以自动DNS解析容器名称到IP地址

5.4.1、自定义桥接网络 

在建立自定以网络时,默认使用桥接模式

[root@docker ~]# docker network create my_net1
 [root@docker ~]# docker network ls

桥接默认是单调递增

桥接也支持自定义子网和网关

 [root@docker ~]# docker network create my_net2 --subnet 192.168.0.0/24 --gateway 192.168.0.100

[root@docker ~]# docker network inspect my_net2
​​​​​​​

5.4.2、为什么要自定义桥接 

[root@docker ~]# docker run -d --name web1 nginx

[root@docker ~]# docker inspect web1


[root@docker ~]# docker run -d --name web2 nginx

[root@docker ~]# docker inspect web2

  •  docker引擎在分配ip时时根据容器启动顺序分配到,谁先启动谁用,是动态变更的
  • 多容器互访用ip很显然不是很靠谱,那么多容器访问一般使用容器的名字访问更加稳定
  • docker原生网络是不支持dns解析的,自定义网络中内嵌了dns 

[root@docker ~]# docker run -d --network my_net1 --name web nginx
[root@docker ~]# docker run -it --network my_net1 --name test busybox

注:不同的自定义网络是不能通讯的

#在rhel7中使用的是iptables进行网络隔离,在rhel9中使用nftpables

[root@docker ~]# nft list ruleset可以看到网络隔离策略

5.4.3、如何让不同的自定义网络互通? 

[root@docker ~]# docker run -d --name web1 --network my_net1 nginx
[root@docker ~]# docker run -it --name test --network my_net2 busybox

#在上面test容器中加入网络eth1

[root@docker ~]# docker network connect my_net1 test
​​​​​​​​​​​​​​

5.4.4、joined容器网络 

  • Joined容器一种较为特别的网络模式,在容器创建时使用--network=container:vm1指定。(vm1指定 的是运行的容器名)
  • 处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用localhost高效快速通 信。

[root@docker ~]# docker run -it --rm --network container:web1 busybox

[root@docker ~]# docker run -it --rm --network container:web1 centos:7

joined网络示例演示:

  • 利用容器部署phpmyadmin管理mysql

1、运行phpmysqladmin 

[root@docker ~]#  docker run -d --name mysqladmin --network my_net1 \
> -e PMA_ARBITRARY=1 \        ##在web页面中可以手动输入数据库地址和端口
> -p 80:80 phpmyadmin:latest

2、运行数据库

[root@docker ~]# docker run -d --name mysql \
> -e MYSQL_ROOT_PASSWORD='zpy' \        #设定数据库密码
> --network container:mysqladmin \        #把数据库容器添加到phpmyadmin容器中
> mysql:5.7

注: 

  • 开启的phpmyadmin容器中是没有数据库的
  • 这里填写的localhost:3306是因为mysql容器和phpmyadmin容器公用一个网络站

 ​​​​​​​​​​​​

看数据库里的命令

docker exec -it mysql bash

mysql -uroot -pzpy

5.5、外网访问docker容器

5.5.1、内网访问外网

5.5.2、外网访问内网

端口映射 -p 本机端口:容器端口来暴漏端口从而达到访问效果

#通过docker-proxy对数据包进行内转

[root@docker ~]# docker run -d --name webserver -p 80:80 nginx:1.23
[root@docker ~]# ps ax

#通过火墙策略来完成浏览内转

[root@docker ~]# iptables -t nat -nL

注:docker-proxy和火墙策略在容器建立端口映射后都会开启,那个传输速录高走那个

删除其中一个,也可以通过另一个通信

5.6、docker跨主机网络

  • 跨主机网络解决方案
    • docker原生的overlay和macvlan
    • 第三方的flannel、weave、calico
  • 众多网络方案是如何与docker集成在一起的
    • libnetwork docker容器网络库
    • CNM (Container Network Model)这个模型对容器网络进行了抽象 

5.6.1、CNM (Container Network Model)

CNM分三类组件

  • Sandbox:容器网络栈,包含容器接口、dns、路由表。(namespace)
  • Endpoint:作用是将sandbox接入network (veth pair)
  • Network:包含一组endpoint,同一network的endpoint可以通信 

5.6.2、macvlan网络方式实现跨主机通信

需要有同时带有两个网卡的两台主机

一个为net模式,一个为进主机模式

这里eth1为进主机模式

以下,两台主机都需要配置

1、打开混杂模式

[root@docker ~]# ifconfig eth1

这样未开

使用这个命令打开

[root@docker ~]# ip link set eth1 promisc on
[root@docker ~]# ifconfig eth1

这样就开了

2、添加macvaln网路

[root@docker ~]# docker network create -d macvlan --subnet 4.4.4.0/24 --gateway 4.4.4.4 -o parent=eth1 mynet1

3、创建容器

指定IP

[root@docker ~]# docker run -it --rm --name test --network mynet1 --ip 4.4.4.1 busybox:latest

[root@docker1 ~]# docker run -it --rm --name test --network mynet1 --ip 4.4.4.2 busybox:latest

这样也不能向外通信,因为不是桥接,这个必须插入可以连接外网的网线才可以通信

但可以实现跨主机通信

六、Docker 数据卷管理及优化

6.1 为什么要用数据卷

6.2、bind mount 数据卷

先在主机上创建文件,方便测试

[root@docker ~]# mkdir /zpy
[root@docker ~]# touch /zpy/zpyfile{1..5}
[root@docker ~]# ls /zpy
zpyfile1  zpyfile2  zpyfile3  zpyfile4  zpyfile5
[root@docker ~]# docker run -it --rm --name test -v /zpy:/data1:rw -v /etc/passwd:/data2/passwd busybox:latest

rw:为读写

ro:为只读

默认为rw

在这里面更改外面也会同时改变

6.3、docker managed 数据卷

  • bind mount必须指定host文件系统路径,限制了移植性
  • docker managed volume 不需要指定mount源,docker自动为容器创建数据卷目录
  • 默认创建的数据卷目录都在 /var/lib/docker/volumes 中
  • 如果挂载时指向容器内已有的目录,原有数据会被复制到volume中

[root@docker volumes]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='zpy' mysql:5.7

当删除mysql容器,但数据卷还是存在时

[root@docker volumes]# docker rm -f mysql

可以清理未使用的 Docker 数据卷

[root@docker ~]# docker volume prune

注:

  • 在执行 docker volume prune 命令之前,请确保你确实不再需要这些数据卷中的数据,因为 该操作是不可逆的,一旦删除数据将无法恢复。
  • 如果有重要的数据存储在数据卷中,建议先进行备份,或者确保数据已经被妥善保存到其他地 方。

建立卷

[root@docker volumes]# docker volume create zpyvol1
[root@docker volumes]# ll zpyvol1/_data/
total 0

查看卷

[root@docker volumes]# docker volume ls

使用建立的数据卷 

[root@docker volumes]# docker run -d --name web1 -p 80:80 -v zpyvol1:/usr/share/nginx/html nginx:latest
[root@docker volumes]# /var/lib/docker/volumes/zpyvol1/_data

6.4、数据卷容器(Data Volume Container) 

数据卷容器(Data Volume Container)是 Docker 中一种特殊的容器,主要用于方便地在多个容器之间 共享数据卷。

1.建立数据卷容器 

 [root@docker ~]# docker run -d --name datavol \
> -v /tmp/data1:/data1:rw \
> -v /tmp/data2:/data2:ro \
> -v /etc/resolv.conf:/etc/hosts busybox

 2.使用数据卷容器

 [root@docker ~]# docker run -it --name test --rm --volumes-from datavol busybox

6.5、bind mount 数据卷和docker managed 数据卷的对比 

相同点: 两者都是 host 文件系统中的某个路径 

不同点:

bind mountdocker managed
volume位置可任意指定/var/lib/docker/volumes
对已有mount point影响隐藏并替换为volume原有数据复制到volume
是否支持单个文件支持不支持只能是目录
权限控制可设置为只读,默认为读写无控制,均为读写
移植性移植性弱,与host path绑定移植性强,无需指定host目录

 6.6、备份与迁移数据卷

1、备份数据卷 

 #建立容器并指定使用卷到要备份的容器

[root@docker ~]# docker run --volumes-from datavol \

-v `pwd`:/backup busybox \         #把当前目录挂在到容器中用于和容器交互保存要备份的容器

tar zcf /backup/data1.tar.gz /data1         #备份数据到本地

2、数据恢复

[root@docker ~]# docker run -it --name test1 -v zpyvol1:/data1 -v `pwd`:/backup busybox /bin/sh -c "tar zxf /backup/data1.tar.gz;/bin/sh"

七、Docker 的安全优化

Docker容器的安全性,很大程度上依赖于Linux系统自身

评估Docker的安全性时,主要考虑以下几个方面:

  • Linux内核的命名空间机制提供的容器隔离安全
  • Linux控制组机制对容器资源的控制能力安全。
  • Linux内核的能力机制所带来的操作权限安全
  • Docker程序(特别是服务端)本身的抗攻击性。
  • 其他安全增强机制对容器安全性的影响

#在rhel9中默认使用cgroup2 但是cgroup2中不利于观察docker的资源限制情况,所以推荐使用 cgroup

[root@docker ~]# grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="systemd.unified_cgroup_hierarchy=0 systemd.legacy_systemd_cgroup_controller"
[root@docker ~]# reboot

1、命名空间隔离的安全

  • 当docker run启动一个容器时,Docker将在后台为容器创建一个独立的命名空间。
  • 命名空间提供了 最基础也最直接的隔离。
  • 与虚拟机方式相比,通过Linux namespace来实现的隔离不是那么彻底。
  • 容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作 系统内核。
  • 在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,比如:磁盘等等

[root@docker ~]# docker run -d --name web nginx:1.23
03ea0212a8c3b70e3f09dfe4f1edd86b4f841639bebdb810c66000d81fe43008

[root@docker proc]# docker inspect web | grep Pid
            "Pid": 2630,
            "PidMode": "",
            "PidsLimit": null,
[root@docker proc]# cd /proc/2630/ns/
[root@docker ns]# ls
cgroup  ipc  mnt  net  pid  pid_for_children  time  time_for_children  user  uts
[root@docker ns]# ls -d /sys/fs/cgroup/memory/docker/03ea0212a8c3b70e3f09dfe4f1edd86b4f841639bebdb810c66000d81fe43008/
/sys/fs/cgroup/memory/docker/03ea0212a8c3b70e3f09dfe4f1edd86b4f841639bebdb810c66000d81fe43008/
[root@docker ns]#

退出后就没有了

[root@docker cgroup]# docker rm -f web

2、控制组资源控制的安全

  • 当docker run启动一个容器时,Docker将在后台为容器创建一个独立的控制组策略集合。
  • Linux Cgroups提供了很多有用的特性,确保各容器可以公平地分享主机的内存、CPU、磁盘IO等 资源。
  • 确保当发生在容器内的资源压力不会影响到本地主机系统和其他容器,它在防止拒绝服务攻击 (DDoS)方面必不可少

#内存资源默认没有被隔离

[root@docker cgroup]# docker run -it --name test busybox:latest

3、内核能力机制

  • 能力机制(Capability)是Linux内核一个强大的特性,可以提供细粒度的权限访问控制。
  • 大部分情况下,容器并不需要“真正的”root权限,容器只需要少数的能力即可。
  • 默认情况下,Docker采用“白名单”机制,禁用“必需功能”之外的其他权限。

4、Docker服务端防护

  • 使用Docker容器的核心是Docker服务端,确保只有可信的用户才能访问到Docker服务。
  • 将容器的root用户映射到本地主机上的非root用户,减轻容器和主机之间因权限提升而引起的安全 问题。
  • 允许Docker 服务端在非root权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。
  • 这些子进程只允许在特定范围内进行操作。

#默认docker是用root用户控制资源的

[root@docker ~]# ls -ld /var/lib/docker/
drwx--x---. 12 root root 171 Aug 30 15:01 /var/lib/docker/

7.1 Docker的资源限制

Linux Cgroups 的全称是 Linux Control Group。

  • 是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
  • 对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。

Linux Cgroups 给用户暴露出来的操作接口是文件系统

  • 它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。
  • 执行此命令查看:mount -t cgroup

  • 在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。
  • 在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录)。
  • 控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定。

#关闭cpu的核心,当cpu都不空闲下才会出现争抢的情况,为了实验效果我们可以关闭一个cpu核心 

7.1.1、限制cpu使用

1.限制cpu的使用量

 因为我只有一个内核,我创建一个容器的话就是满负荷的效果

[root@docker cgroup]# docker run -it --name test --rm ubuntu:latest
root@0a6ba9610a75:/# dd if=/dev/zero of=/dev/null &
[1] 8
root@0a6ba9610a75:/# top

如果我们要限制它cpu的使用量

[root@docker ~]# docker run -it --rm --name test --cpu-period 10000 --cpu-quota 2000 ubuntu:latest
root@6bf1a0ba605a:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@6bf1a0ba605a:/# top

2、限制cpu的优先级

[root@docker ~]# docker run -it --rm --name test ubuntu:latest
root@35a4e7bbd573:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@35a4e7bbd573:/# top

再创建一个容器和他争抢

[root@docker ~]# docker run -it --name test1 --rm --cpu-shares 100 ubuntu:latest
root@2790423473fd:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@2790423473fd:/# top

#设定cpu优先 级,最大为1024,值越大优先级越高

7.1.2、限制内存使用

#开启容器并限制容器使用内存大小

[root@docker ~]# docker run -d --name test --memory 200M --memory-swap 200M nginx:1.23
6969ddebbdbad1ccc474f9ef5d665191a9234cf8d48ec3256eff8a6545ab00b9

#查看容器内存使用限制

[root@docker docker]# pwd
/sys/fs/cgroup/memory/docker
[root@docker docker]# cd 6969ddebbdbad1ccc474f9ef5d665191a9234cf8d48ec3256eff8a6545ab00b9/
[root@docker 6969ddebbdbad1ccc474f9ef5d665191a9234cf8d48ec3256eff8a6545ab00b9]# cat memory.limit_in_bytes
209715200
[root@docker 6969ddebbdbad1ccc474f9ef5d665191a9234cf8d48ec3256eff8a6545ab00b9]# cat memory.memsw.limit_in_bytes
209715200

#测试容器内存限制,在容器中我们测试内存限制效果不是很明显,可以利用工具模拟容器在内存中写入数据

[root@docker ~]# yum install *.rpm -y

#在系统中/dev/shm这个目录被挂在到内存中

[root@docker ~]# df -h
Filesystem             Size  Used Avail Use% Mounted on
devtmpfs               4.0M     0  4.0M   0% /dev
tmpfs                  369M     0  369M   0% /dev/shm
tmpfs                  148M  4.5M  143M   4% /run
tmpfs                  4.0M     0  4.0M   0% /sys/fs/cgroup
/dev/mapper/rhel-root   36G  6.3G   29G  18% /
/dev/sda1              960M  304M  657M  32% /boot
/dev/sr0                11G   11G     0 100% /rhel9
tmpfs                   74M   52K   74M   1% /run/user/42
tmpfs                   74M   36K   74M   1% /run/user/0
overlay                 36G  6.3G   29G  18% /var/lib/docker/overlay2/8eacd8a224555075a3e0

bc9d082c0fcba84e6d8a7b5925267caa280bd06d61cd/merged
[root@docker ~]# dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
200+0 records in        #读入
200+0 records out        #写出
209715200 bytes (210 MB, 200 MiB) copied, 0.222368 s, 943 MB/s

cgexec -g memory:doceker/容器id -g表示使用指定控制器类型 

[root@docker ~]# cgexec -g memory:docker/fcd6e70a058f360cf4c393b96c6cb3aba53363763ea0c02d44b53f2c9940f306/ dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=150

也可以自建控制器

[root@docker ~]# mkdir -p /sys/fs/cgroup/memory/x1/
[root@docker ~]# ls /sys/fs/cgroup/memory/x1/

#内存可用大小限制

[root@docker ~]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.limit_in_bytes

#此控制器被那个进程调用

[root@docker ~]# cat /sys/fs/cgroup/memory/x1/tasks
[root@docker ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=100

[root@docker ~]# free -m

#内存溢出部分被写入swap交换分区

[root@docker ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=300
[root@docker ~]# free -m

[root@docker ~]# rm -fr /dev/shm/bigfile
[root@docker ~]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.memsw.limit_in_bytes
[root@docker ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
Killed
[root@docker ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=199
Killed
[root@docker ~]# rm -fr /dev/shm/bigfile
[root@docker ~]# cgexec -g memory:x1 dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=190

7.1.3、限制docker的磁盘io

未做限制时

[root@docker ~]# docker run -it --name test --rm ubuntu:latest
root@ea604152fc15:/# dd if=/dev/zero of=file bs=1M count=300
300+0 records in
300+0 records out
314572800 bytes (315 MB, 300 MiB) copied, 0.685162 s, 459 MB/s
root@ea604152fc15:/# dd if=/dev/zero of=file bs=1M count=500
500+0 records in
500+0 records out
524288000 bytes (524 MB, 500 MiB) copied, 1.04747 s, 501 MB/s

对IO进行限速

#指定容器使用磁盘io的速率

#/dev/sr0是指定系统的磁盘,30M即每秒30M数据

[root@docker ~]# docker run -it --rm --device-write-bps /dev/sr0:30M ubuntu

#开启容器后会发现速度和设定不匹配, 是因为系统的缓存机制
root@5ff90bb742d3:/# dd if=/dev/zero of=bigfile

现在还没有限速,因为dd一般是存储到内存里,然后慢慢存到硬盘里

直接写入硬盘里,这样写才会限速

#设定dd命令直接写入磁盘

​​​​​​​root@5ff90bb742d3:/# dd if=/dev/zero of=bigfile bs=1M count=100 oflag=direct

7.2.3 容器特权

--privileged 参数开启容器,容器获得权限近乎于宿主机的root用户

[root@docker ~]# docker run --rm -it --privileged busybox:latest

7.2.4、容器特权的白名单

  • --privileged=true 的权限非常大,接近于宿主机的权限
  • 为了防止用户的滥用,需要增加限制,只提供 给容器必须的权限
  • 此时Docker 提供了权限白名单的机制,使用--cap-add添加必要的权限

#限制容器对网络有root权限

[root@docker ~]# docker run --rm -it --cap-add NET_ADMIN busybox:latest

八、容器编排工具Docker Compose

8.1、Docker Compose 概述

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。

其是官方的一个开源项目,托管到github上 https://github.com/docker/compose 

工作原理

1. 读取配置文件:

  • Docker Compose 读取 YAML 配置文件,解析其中定义的服务和参数。

2. 创建容器:

  • 根据配置文件中的定义,Docker Compose 调用 Docker 引擎创建相应的容器。
  • 它会下载所需 的镜像(如果本地没有),并设置容器的各种参数。

3. 管理容器生命周期:

  • Docker Compose 监控容器的状态,并在需要时启动、停止、重启容器。
  • 它还可以处理容器的故障恢复,例如自动重启失败的容器。 

Docker Compose 中的管理层

1. 服务 (service) 一个应用的容器,实际上可以包括若干运行相同镜像的容器实例

2. 项目 (project) 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中 定义

3. 容器(container)容器是服务的具体实例,每个服务可以有一个或多个容器。容器是基于服务定义 的镜像创建的运行实例 

8.2、Docker Compose 的常用命令参数

首先,我们先写一个yaml脚本来方便测试

[root@docker ~]# mkdir test/

[root@docker ~]# cd test/
[root@docker test]# vim docker-compose.yml

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"

  testnode:
    image: busybox:latest
    command: ["/bin/sh","-c","sleep 10000"]

8.2.1、服务管理

1. docker-compose up :

  • 可以使用 -d 参数在后台启动服务
  • 可以使用-f 来指定yml文件

运行compose是一定在yaml文件所在目录里

如果将docker-compose.yml文件改名字

[root@docker test]# mv docker-compose.yml zpy.yml
[root@docker test]# ls
zpy.yml

默认寻找docker-compose.yml文件,改名后就找不到了
[root@docker test]# docker compose up -d
no configuration file provided: not found

只能-f指定文件

为了方便后面的测试,我把文件名改回来

[root@docker test]# mv zpy.yml docker-compose.yml

运行的容器

2. docker-compose down :

  • 停止并删除配置文件中定义的所有服务以及相关的网络和存储卷。

[root@docker test]# docker compose down

3.docker-compose stop :

  • 停止正在运行的服务

[root@docker test]# docker compose stop

4. docker-compose start :

  • 启动已经存在的服务,但不会创建新的服务。

[root@docker test]# docker compose start

5. docker-compose restart :

[root@docker test]# docker compose restart

8.2.2、服务状态查看

1. docker-compose ps :

  • 列出正在运行的服务以及它们的状态,包括容器 ID、名称、端口映射等信息。

[root@docker test]# docker compose ps

若要指定文件查看,加参数 -f

2. docker-compose logs :

  • 查看服务的日志输出。可以指定服务名称来查看特定服务的日志。

[root@docker test]# docker compose logs web

8.2.3、构建和重新构建服务(了解)

1. docker-compose build :

  • 构建配置文件中定义的服务的镜像
  • 可以指定服务名称来只构建特定的服务

[root@docker ~]# mkdir docker
[root@docker ~]# cd /root/docker
[root@docker docker]# vim Dockerfile

[root@docker docker]# cat Dockerfile
FROM busybox:latest
RUN touch /zpyfile1
[root@docker docker]# cat zpy
FROM busybox:latest
RUN touch /zpyfile2

[root@docker test]# vim docker-compose.yml

services:
  test1:
    image: test1
    build:
      context: /root/docker
      dockerfile: Dockerfile
    command: ["/bin/sh","-c","sleep 100000"]
    container_name: zpy1

  test2:
    image: test2
    build:
      context: /root/docker
      dockerfile: zpy
    command: ["/bin/sh","-c","sleep 100000"]
    container_name: zpy2

#构建 services中的所有

[root@docker test]# docker compose  build 

#构建 services中的test1 

[root@docker test]# docker rmi test1:latest
[root@docker test]# docker rmi test2:latest
[root@docker test]# docker compose  build test1

2. docker-compose up --build :

  • 启动服务并在启动前构建或重新构建镜像。

#会去仓库拉去镜像

[root@docker test]# docker compose up -d

#会先构建镜像后启动容器

[root@docker test]# docker compose up test1 --build -d

8.2.4、其他操作

1. docker-compose exec :

  • 在正在运行的服务容器中执行命令

[root@docker test]# vim zpy.yml

services:
  test:
    image: busybox:latest
    command: ["/bin/sh","-c","sleep 3000"]
    restart: always
    container_name: busybox1


[root@docker test]# docker compose -f zpy.yml up -d
[root@docker test]# docker compose -f zpy.yml exec -it test /bin/sh
/ # exit

2. docker-compose pull :

  • 拉取配置文件中定义的服务所使用的镜像

[root@docker test]#  docker compose -f zpy.yml pull
[+] Pulling 2/2

  ✔ test Pulled

  ✔ ec562eabd705 Pull complete

3. docker-compose config :

  • 验证并查看解析后的 Compose 文件内容

没问题就打印

[root@docker test]#  docker compose -f zpy.yml config
name: test
services:
  test:
    command:
      - /bin/sh
      - -c
      - sleep 3000
    container_name: busybox1
    image: busybox:latest
    networks:
      default: null
    restart: always
networks:
  default:
    name: test_default

加上-q就打不打印
[root@docker test]#  docker compose -f zpy.yml config -q

8.3、Docker Compose 的yml文件

8.3.1、服务(services)

1. 服务名称(service1_name/service2_name 等)

  • 每个服务在配置文件中都有一个唯一的名称,用于在命令行和其他部分引用该服务

2. 镜像(image)

  • 指定服务所使用的 Docker 镜像名称和标签。例如, image: nginx:latest 表示使用 nginx 镜像的最新版本

3. 端口映射(ports)

  • 将容器内部的端口映射到主机的端口,以便外部可以访问容器内的服务

4. 环境变量(environment)

  • 为容器设置环境变量,可以在容器内部的应用程序中使用

设置环境变 量 VAR1 的值为 value1

var1=value1

5. 存储卷(volumes)

  • 将主机上的目录或文件挂载到容器中,以实现数据持久化或共享

#只读挂在本地文件到指定位置

volumes:

  - /etc/passwd:/tmp/passwd:ro

6. 网络(networks)

  • 将服务连接到特定的网络,以便不同服务的容器可以相互通信

network_mode: bridge #使用本机自带bridge网络

7. 命令(command)

  • 覆盖容器启动时默认执行的命令、

command: ["/bin/sh","-c","sleep3000"]

8.3.2、网络(networks)

  • 定义 Docker Compose 应用程序中使用的网络。可以自定义网络名称和驱动程序等属性。
  • 默认情况下docker compose 在执行时会自动建立网路

1、使用已有资源

[root@docker test]# vim docker-compose.yml

services:
  test1:
    image: busybox:latest
    command: ["/bin/sh","-c","sleep 100000"]
    container_name: zpy1
    network_mode: default

networks:
  default:
    external: true
    name: bridge


[root@docker test]#  docker compose -f zpy.yml up -d

2、自建网络

[root@docker test]# vim docker-compose.yml

test1:
    image: busybox:latest
    command: ["/bin/sh","-c","sleep 100000"]
    container_name: zpy1
    networks:
      - mynet1

networks:

  mynet1:
    driver: bridge

3、指定IP和网关

[root@docker test]# vim docker-compose.yml

services:
  test1:
    image: busybox:latest
    command: ["/bin/sh","-c","sleep 100000"]
    container_name: zpy1
    networks:
      - mynet1
      - mynet2

networks:
  mynet1:
    driver: bridge

  mynet2:
    ipam:
      driver: default
      config:
         - subnet: 172.26.0.0/24
           gateway: 172.26.0.254
[root@docker test]# docker compose  up -d

8.3.3、存储卷(volumes)

  • 定义 Docker Compose 应用程序中使用的存储卷。可以自定义卷名称和存储位置等属性。 

services:
  test:
    image: busybox:latest
    container_name: zpy
    command: ["/bin/sh","-c","sleep 3000"]
    restart: always
    volumes:
      - data: /test
      - /etc/passwd: /passwd:ro

volumes:
  data:
    name: timingzpy

8.4、企业示例

[root@docker test]# mkdir /var/lib/docker/volumes/conf/

[root@docker test]# dnf install haproxy -y --downloadonly --downloaddir=/mnt
[root@docker test]# cd /mnt
[root@docker mnt]# ls
haproxy-2.4.22-3.el9_3.x86_64.rpm  hgfs
[root@docker mnt]# rpm2cpio haproxy-2.4.22-3.el9_3.x86_64.rpm | cpio -id
13488 blocks
[root@docker mnt]# ls
etc  haproxy-2.4.22-3.el9_3.x86_64.rpm  hgfs  usr  var
[root@docker mnt]# cd etc/haproxy/
[root@docker haproxy]# ls
conf.d  haproxy.cfg
[root@docker haproxy]# cp haproxy.cfg /var/lib/docker/volumes/conf/
[root@docker haproxy]# cd /var/lib/docker/volumes/conf/
[root@docker conf]# ls
haproxy.cfg
[root@docker conf]# vim haproxy.cfg

listen webcluster
    bind *:80
    balance roundrobin
    server web1 webserver1:80 check inter 3 fall 3 rise 5
    server web2 webserver2:80 check inter 3 fall 3 rise 5
[root@docker conf]# vim ~/.vimrc

set ts=4 sw=4 ai et

[root@docker ~]# cd test/
[root@docker test]# vim haproxy.yml

services:
  web1:
    image: nginx:latest
    container_name: webserver1
    restart: always
    expose:
      - 80
    volumes:
      - data_web1:/usr/share/nginx/html
    networks:
      - internel

  web2:
    image: nginx:latest
    container_name: webserver2
    restart: always
    expose:
      - 80
    volumes:
      - data_web2:/usr/share/nginx/html
    networks:
      - internel

  haproxy:
    image: haproxy:2.3
    container_name: haproxy
    restart: always
    ports:
      - "80:80"

    volumes:
      - /var/lib/docker/volumes/conf/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
    networks:
      - internel
      - extrnal

networks:
  internel:
    driver: bridge

  extrnal:
    driver: bridge

volumes:
  data_web1:
    name: data_web1

  data_web2:
    name: data_web2
 

这里涉及的两个镜像(nginx:latest,haproxy:2.3),需要自己拉取或者上传导入

haproxy策略里的两个服务器名称需要和web1,web2创建的容器名称相同

后就可以创建容器了

[root@docker test]# docker compose -f haproxy.yml up -d

echo webserver1 > /var/lib/docker/volumes/data_web1/_data/index.html
echo webserver2 > /var/lib/docker/volumes/data_web2/_data/index.html
 

测试:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值