Docker

一 、Docker简介及部署方法

1 Docker简介

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

2008 年LXC(LinuXContiainer)发布,但是没有行业标准,兼容性非常差 docker2013年首次发布,由Docker, Inc开发

1.1 什么是docker?

  • Docker是管理容器的引擎,为应用打包、部署平台,而非单纯的虚拟化技术
  • 它具有以下几个重要特点和优势:
    1. 轻量级虚拟化:Docker 容器相较于传统的虚拟机更加轻量和高效,能够快速启动和停止,节省系统资源。 例如,启动一个 Docker 容器可能只需要几秒钟,而启动一个虚拟机则可能需要几分钟。
    1. 一致性:确保应用程序在不同的环境中(如开发、测试、生产)具有一致的运行表现。 无论在本地还是云端,应用的运行环境都能保持相同,减少了因环境差异导致的问题。
    1. 可移植性:可以轻松地将 Docker 容器从一个平台迁移到另一个平台,无需担心依赖和环境配置的差 异。 比如,在本地开发的容器可以无缝部署到云服务器上。
    1. 高效的资源利用:多个 Docker 容器可以共享主机的操作系统内核,从而更有效地利用系统资源。
    1. 易于部署和和扩展:能够快速部署新的应用实例,并且可以根据需求轻松地进行水平扩展。

总之,Docker 极大地简化了应用程序的开发、部署和管理流程,提高了开发效率和运维的便利性。 它在现代软件开发和云计算领域得到了广泛的应用。

1.2 docker在企业中的应用场景

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

IaaS(Infrastructure as a Service),即基础设施即服务

PaaS是(Platform as a Service)即指平台即服务

SaaS(Software as a Service)软件运营服务是

1.3 docker与虚拟化的对比

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

1.4 docker的优势

  • 对于开发人员:Build once、Run anywhere,统一环境,消除环境差异,一次构建多环境运行。
  • 对于运维人员:Configure once、Run anything,标准化部署,资源轻量、快速部署,便于迁移与自动化运维。

2 部署docker

2.1 容器工作方法

2.2 部署容器

2.2.1 配置软件仓库并安装docker-ce
bash 复制代码
# 利用阿里云部署软件仓库
[root@docker-node1 ~]# cd /etc/yum.repos.d
[root@docker-node1 yum.repos.d]# cat docker.repo
[docker]
name=docker-ce
baseurl=https://mirrors.aliyun.com/docker-ce/linux/rhel/9/x86_64/stable
gpgcheck=0

[root@docker-node1 ~]# dnf makecache
[root@docker-node1 ~]# dnf remove podman -y

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

[root@docker-node1 ~]# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true

[root@docker-node1 ~]# echo br_netfilter > /etc/modules-load.d/docker_mod.conf
[root@docker-node1 ~]# modprobe -a br_netfilter

[root@docker-node1 ~]# cat  > /etc/sysctl.d/docker.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

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

[root@docker-node1 ~]# systemctl enable --now docker
2.2.2 查看是否安装成功
2.2.3 配置docker加速
bash 复制代码
[root@docker-node1 ~]# cat > /etc/docker/daemon.json <<EOF
{
    "registry-mirrors": ["https://docker.1ms.run"]
}
EOF
[root@docker-node1 ~]# systemctl restart docker

[root@docker-node1 ~]# docker info
 Registry Mirrors:
  https://docker.1ms.run/

二 、Docker的基本操作

1 Docker镜像管理

1.1 搜索镜像

bash 复制代码
[root@Docker-node1 ~]# docker search nginx
参数 说明
NAME 镜像名称
DESCRIPTION 镜像说明
STARS 点赞数量
OFFICIAL 是否是官方的

1.2 拉取镜像

bash 复制代码
# 从镜像仓库中拉取镜像
[root@docker-node1 ~]# docker pull busybox
[root@docker-node1 ~]# docker pull nginx:1.26-alpine        #alpine 版本:nginx镜像的最小安装发型版本
 
# 查看本地镜像
[root@docker-node1 ~]# docker images

1.3 查看镜像信息

bash 复制代码
[root@docker-node1 ~]# docker image inspect nginx

1.4 导出镜像

bash 复制代码
# 保存镜像
[root@docker-node1 ~]# docker image save nginx:latest -o nginx-latest.tar.gz
[root@docker-node1 ~]# docker image save nginx:latest nginx:1.26-alpine -o nginx.tag.gz
 
# 保存所有镜像
[root@docker-node1 ~]# docker save `docker images | awk 'NR>1{print $1":"$2}'` -
o images.tar.gz

-o:指定导出镜像的位置;

可以同时导出多个镜像到一个文件中;

指定.tar.gz 可以导出并压缩。

1.5 删除镜像

bash 复制代码
[root@docker-node1 ~]# docker rmi nginx:latest
[root@docker-node1 ~]# docker rmi `docker images | awk 'NR>1{print $1":"$2}'`
 
# 删除所有镜像
docker rm -f $(docker ps -aq)

2 容器的常用操作

2.1 启动容器

bash 复制代码
[root@docker-node1 ~]# docker run -d --name nginx -p 80:80 nginx:latest
[root@docker-node1 ~]# docker run -it --name nginx -p 80:80 nginx:latest
# 进入到容器中,按<ctrl>+<d>退出并停止容器,# 按<ctrl>+<pq>退出但不停止容器
 
# 重新进入容器
[root@docker-node1 ~]# docker attach nginx
 
# 在容器中执行命令
[root@docker ~]# docker exec -it test ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

-d #后台运行

-i #交互式运行

-t #打开一个终端

--name #指定容器名称

-p #端口映射

-p 80:8080 #把容器8080端口映射到本机80端口

--rm #容器停止自动删除容器

--network #指定容器使用的网络

2.2 查看容器运行信息

bash 复制代码
[root@docker-node1 ~]# docker ps                 # 查看当前运行容器
[root@docker-node1 ~]# docker ps -a              # 查看所有容器
[root@docker-node1 ~]# docker inspect busybox    # 查看容器运行的详细信息

2.3 停止和运行容器

bash 复制代码
[root@docker-node1 ~]# docker stop busybox     # 停止容器
[root@docker-node1 ~]# docker kill busybox     # 杀死容器,可以使用信号
[root@docker-node1 ~]# docker start busybox    # 开启停止的容器

容器内的第一个进程必须一直处于运行的状态,否则这个容器,就会处于退出状态!

2.4 删除容器

bash 复制代码
[root@docker-node1 ~]# docker rm centos7         # 删除停止的容器
[root@docker-node1 ~]# docker rm -f busybox      # 删除运行的容器
[root@docker-node1 ~]# docker container prune -f # 删除所有停止的容器

2.5 容器内容提交

默认情况下,容器被删除后,在容器中的所有操作都会被清理,包括要保存的文件。如果想永久保存,那么我们需要把动作提交,提交后会生成新的镜像。当我们在运行新镜像后即可看到我们提交的内容

bash 复制代码
[root@docker-node1 docker]# docker run -it --name test busybox
/ # touch leefile                            # 在容器中建立文件
/ # ls
bin      etc      leefile  lib64    root     tmp      var
dev      home     lib      proc     sys      usr
/ # 
 
[root@docker-node1 docker]# docker rm test         # 删掉容器后
test
 
[root@docker-node1 docker]# docker run -it --name test busybox        # 删掉容器后开启新的容器文件不存在
/ # ls
bin    dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # 
 
[root@docker-node1 ~]# docker commit -m "add leefile" test busybox:v1
sha256:648560550edc2b23a2176009ad9751db745c89df0f46d169f1aea249f9387e8f
[root@docker-node1 ~]# docker images 
REPOSITORY           TAG           IMAGE ID       CREATED         SIZE
busybox              v1            648560550edc   6 seconds ago   4.26MB 
 
[root@docker-node1 ~]# docker image history busybox:v1 
IMAGE          CREATED          CREATED BY                          SIZE      COMMENT
648560550edc   34 seconds ago   sh                                  3B        add leefile
65ad0d468eb1   15 months ago    BusyBox 1.36.1 (glibc), Debian 12   4.26MB    

此方法不利于企业审计,所以不推荐使用,在企业中我们多用Dockerfile来构建镜像

2.6 系统中的文件和容器中的文件传输

bash 复制代码
# 把容器中的文件复制到本机
[root@docker-node1 ~]# docker cp test2:/leefile /mnt 
Successfully copied 1.54kB to /mnt
 
# 把本机文件复制到容器中
[root@docker-node1 ~]# docker cp /etc/fstab test2:/fstab     

2.7 查询容器内部日志

bash 复制代码
[root@docker-node1 ~]# docker logs

三、 docker镜像构建

1 docker镜像结构

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

2 镜像运行的基本原理

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

3 镜像获得方式

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

4 镜像构建

4.1 构建参数

指令 说明
FROM 指定 base 镜像 eg: FROM busybox:version
COPY 复制文件 eg: COPY file /file 或者 COPY "file","/"
MAINTAINER 指定作者信息,比如邮箱 eg: MAINTAINER user@example.com在最新版的 docker 中用 LABEL KEY="VALUE" 代替
ADD 功能和 copy 相似,指定压缩文件或 url eg: ADD test.tar/mnt 或者 eg: ADD http://ip/test.tar/mnt
ENV 指定环境变量 eg: ENV FILENAME test
EXPOSE 暴露容器端口 eg: EXPOSE 80
VOLUME 申明数据卷,通常指数据挂载点 eg: VOLUME "/var/www/html"
WORKDIR 切换路径 eg: WORKDIR /mnt
RUN 在容器中运行的指令 eg: touch file
CMD 在启动容器时自动运行动作,可以被覆盖 eg: CMD echo FILENAME 会调用 shell 解析;eg: CMD \["/bin/sh","-c","echo FILENAME"] 不调用 shell 解析
ENTRYPOINT 和 CMD 功能和用法类似,但动作不可被覆盖
bash 复制代码
# FROM COPY 和MAINTAINER
[root@docker-node1 ~]# mkdir docker/
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# touch leefile 
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest				# 指定使用的基础镜像
MAINTAINER lee@xicheng.org		# 指定作者信息
COPY leefile /						# 复制当前目录文件到容器指定位置,leefile必须在当前目录中
 
[root@docker-node1 docker]# docker build -t example:v1 .		# 构建镜像

# ADD
[root@docker-node1 docker]# touch file{1..3}
[root@docker-node1 docker]# tar zcf leefile.gz file* 
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
MAINTAINER lee@xicheng.org
COPY leefile /
ADD leefile.gz /
 
[root@docker-node1 docker]# docker build -t example:v2 .
 
[root@docker-node1 docker]# docker run -it --rm --name test example:v2 
/ # ls
bin    etc    file1  file3  lib    proc   sys    usr
dev    file   file2  home   lib64  root   tmp    var
  
# ENV CMD1
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
MAINTAINER lee@xicheng.org
ENV NAME lee
CMD echo $NAME
 
[root@docker-node1 docker]# docker build -t example:v3 .
 
[root@docker-node1 docker]# docker run -it --rm --name test example:v3
lee
 
# CMD2
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
MAINTAINER lee@xicheng.org
ENV NAME lee
#CMD echo $NAME
CMD ["/bin/echo", "$NAME"]
#CMD ["/bin/sh", "-c", "/bin/echo $NAME"]
 
[root@docker-node1 docker]# docker run -it --rm --name test example:v3 sh
lee
[root@docker-node1 docker]# docker rmi example:v3 
 

# EXPOSE VOLUME VOLUME
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
MAINTAINER lee@xicheng.org
ENV NAME lee
EXPOSE 80 443
VOLUME /var/www/html
WORKDIR /var/www/html
RUN touch file
 
[root@docker-node1 docker]# docker build -t example:v4 .
[root@docker-node1 docker]# docker run -it --rm --name test example:v4 
/var/www/html 

4.2 Dockerfile实例

bash 复制代码
# 一、建立构建目录,编写构建文件
[root@docker-node1 ~]# mdkir docker
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# cp ~/nginx-1.23.tar.gz .
 
[root@docker-node1 ~]# docker load -i /mnt/centos-7.tar.gz 
Loaded image: centos:7
 
[root@docker-node1 docker]# cat Dockerfile 
FROM centos:7
ADD nginx-1.23.tar.gz /mnt
WORKDIR /mnt/nginx-1.23
RUN yum install -y gcc make pcre-devel openssl-devel
RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc
RUN ./configure --with-http_ssl_module --with-http_stub_status_module
RUN make
RUN make install
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

# 二、通过dockerfile生成镜像
--------------------------------------------------------------------------------------
# 解决yum install报错
ERROR: failed to solve: process "/bin/sh -c yum install gcc make pcre-devel openssl-devel" did not complete successfully: exit code: 1
 
1.添加新sr1并挂载到centos镜像
 
2.下载web服务
[root@docker-node1 docker]# dnf install httpd -y

# 更改web端口
[root@docker-node1 docker]# vim /etc/httpd/conf/httpd.conf 
[root@docker-node1 docker]# systemctl restart httpd 
[root@docker-node1 docker]# mkdir -p /var/www/html/rhel7.9
[root@docker-node1 docker]# mount /dev/sr1 /var/www/html/rhel7.9/
mount: /var/www/html/rhel7.9: WARNING: source write-protected, mounted read-only.
 
#查看容器IP
[root@docker-node1 docker]# docker inspect centos
 "IPAddress": "172.17.0.2",
 
[root@docker-node1 yum.repos.d]# docker run -it --name centos centos:7
[root@4b97ad6eb719 /]# ls
anaconda-post.log  bin  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@4b97ad6eb719 /]# cd /etc/yum.repos.d/
[root@4b97ad6eb719 yum.repos.d]# ls
CentOS-Base.repo  CentOS-Debuginfo.repo  CentOS-Sources.repo  CentOS-fasttrack.repo
CentOS-CR.repo    CentOS-Media.repo      CentOS-Vault.repo    CentOS-x86_64-kernel.repo
[root@4b97ad6eb719 yum.repos.d]# rm -rf *
[root@4b97ad6eb719 yum.repos.d]# vi centos7.repo
[root@4b97ad6eb719 yum.repos.d]# cat centos7.repo 
[centos7]
name=centos7
baseurl=http://172.17.0.1:8888/rhel7.9
gpgcheck=0
 
# 提交
[root@docker-node1 docker]# docker commit -m "add repo" centos centos:repo
sha256:8629c14342c7fc149b23f5fe6c23b2b93d67bba025503f49fac82b9de7c4ec70
[root@docker-node1 docker]#  docker images 
REPOSITORY                      TAG           IMAGE ID       CREATED          SIZE
centos                          repo          8629c14342c7   21 seconds ago   204MB
 
[root@4b97ad6eb719 yum.repos.d]# exit
exit
[root@docker-node1 yum.repos.d]# docker rm centos
centos
 
[root@docker-node1 docker]# vim Dockerfile
FROM centos:repo
ADD nginx-1.23.tar.gz /mnt
WORKDIR /mnt/nginx-1.23
RUN yum install gcc make pcre-devel openssl-devel -y
RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc
RUN ./configure --preifx=/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;"]
--------------------------------------------------------------------------------------
[root@docker-node1 docker]# docker build -t webserver:v1 .

# 三、测试镜像可用性
[root@docker-node1 docker]# docker images webserver
[root@docker-node1 docker]# docker history webserver:v1
[root@docker-node1 docker]# docker run -d --name checkimage webserver

# 四、查看容器详情
[root@docker-node1 docker]# docker inspect web1

5 镜像优化方案

5.1 镜像优化策略

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

5.2 镜像优化示例

方法1:缩减镜像层

bash 复制代码
[root@docker-node1 docker]# vim Dockerfile
FROM centos:7 AS build
ADD nginx-1.23.3.tar.gz /mnt
WORKDIR /mnt/nginx-1.23.3
RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx1.23.3 && yum clean all
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@docker-node1 docker]# docker build -t webserver:v2 .
[root@docker-node1 docker]# docker images webserver

方法2:多阶段构建

bash 复制代码
[root@docker-node1 docker]# vim Dockerfile
FROM centos:7 AS build
ADD nginx-1.23.3.tar.gz /mnt
WORKDIR /mnt/nginx-1.23.3
RUN yum install -y gcc make pcre-devel openssl-devel && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --with-http_ssl_module --with-http_stub_status_module && make && make install && cd .. && rm -fr nginx1.23.3 && yum clean all
FROM centos:7
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;"]
[root@docker-node1 docker]# docker build -t webserver:v3 .
[root@docker-node1 docker]# docker images webserver

方法3:使用最精简镜像

使用google提供的最精简镜像

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

下载镜像:docker pull gcr.io/distroless/base

四 docker 镜像仓库的管理

1 什么是docker仓库

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

它就像是一个大型的镜像仓库,开发者可以将自己创建的 Docker 镜像推送到仓库中,也可以从仓库中拉取所需的镜像。

Docker 仓库可以分为公共仓库和私有仓库:

  • 公共仓库,如 Docker Hub,任何人都可以访问和使用其中的镜像。许多常用的软件和应用都有在 Docker Hub 上提供的镜像,方便用户直接获取和使用。例如,您想要部署一个 Nginx 服务器,就可以从 Docker Hub 上拉取 Nginx 的镜像。
  • 私有仓库则是由组织或个人自己搭建和管理的,用于存储内部使用的、不希望公开的镜像。比如,一家企业为其特定的业务应用创建了定制化的镜像,并将其存储在自己的私有仓库中,以保证安全性和控制访问权限。

通过 Docker 仓库,开发者能够方便地共享和复用镜像,加速应用的开发和部署过程。

2 docker hub

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

Docker Hub 是 Docker 官方提供的一个公共的镜像仓库服务。

它是 Docker 生态系统中最知名和广泛使用的镜像仓库之一,拥有大量的官方和社区贡献的镜像。

以下是 Docker Hub 的一些关键特点和优势:

  1. 丰富的镜像资源:涵盖了各种常见的操作系统、编程语言运行时、数据库、Web 服务器等众多应用 的镜像。 例如,您可以轻松找到 Ubuntu、CentOS 等操作系统的镜像,以及 MySQL、Redis 等数据库 的镜像。
  2. 官方支持:提供了由 Docker 官方维护的一些重要镜像,确保其质量和安全性。
  3. 社区贡献:开发者们可以自由上传和分享他们创建的镜像,促进了知识和资源的共享。
  4. 版本管理:对于每个镜像,通常都有多个版本可供选择,方便用户根据需求获取特定版本。
  5. 便于搜索:用户可以通过关键词轻松搜索到所需的镜像。

docker hub的使用方法

bash 复制代码
#登陆官方仓库
[root@docker-node1 ~]# docker login
 
#登陆信息保存位置
[root@docker-node1 ~]# cat .docker/config.json 

3 docker仓库的工作原理

仓库中的三个角色

index docker索引服务,负责并维护有关用户帐户、镜像的校验以及公共命名空间的信息。

registry docker仓库,是镜像和图表的仓库,它不具有本地数据库以及不提供用户认证,通过Index Auth service的Token的方式进行认证

Registry Client Docker充当registry客户端来维护推送和拉取,以及客户端的授权。

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的请求传递镜像到客户端

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 搭建docker的私有仓库

4.1 为什么搭建私有仓库

docker hub虽然方便,但是还是有限制

  • 需要internet连接,速度慢
  • 所有人都可以访问
  • 由于安全原因企业不允许将镜像放到外网

好消息是docker公司已经将registry开源,我们可以快速构建企业私有仓库 地址:https://docs.docker.com/registry/deploying/

4.2 搭建简单的Registry仓库

bash 复制代码
# 1.下载Registry镜像
[root@docker ~]# docker pull registry
 
# 2.开启Registry
[root@docker ~]# docker run -d -p 5000:5000 --restart=always --name registry 
registry
 
# 3.上传镜像到仓库中
# 给要上传的经镜像打标签
[root@docker-node1 ~]# docker tag busybox:latest 172.25.250.100:5000/busybox:latest
 
# 如果速度慢可以用docker加速器
[root@docker-node1 ~]# cat /etc/docker/daemon.json 
{
   "insecure-registries" : ["http://172.25.250.100:5000"]
}
 
[root@docker-node1 ~]# systemctl daemon-reload 
[root@docker-node1 ~]# systemctl start docker
 
 
# docker在上传的过程中默认使用https,但是我们并没有建立https认证需要的认证文件所以会报错
[root@docker-node1 ~]# docker push 172.25.250.100:5000/busybox:latest 
The push refers to repository [172.25.250.100:5000/busybox]
d51af96cf93e: Pushed 
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527
 
# 4.查看镜像上传
[root@docker-node1 ~]# curl 172.25.250.100:5000/v2/_catalog
{"repositories":["busybox"]}

4.3 为Registry提加密传输

bash 复制代码
# 生成认证key和证书
[root@docker-node1 ~]# openssl req -newkey rsa:4096 \
-nodes -sha256 -keyout certs/exam.com.key \
-addext "subjectAltName = DNS:reg.exam.com" \		# 指定备用名称
-x509 -days 365 -out certs/exam.com.crt
 
# 启动registry仓库
[root@docker-node1 ~]# 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/exam.com.crt \
> -e REGISTRY_HTTP_TLS_KEY=/certs/exam.com.key registry
 
测试:
[root@docker-node1 ~]# docker push reg.exam.com/busybox:latest    # docker客
户端没有key和证书
Error response from daemon: Get "https://reg.exam.com/v2/": tls: failed to
verify certificate: x509: certificate signed by unknown authority
 
# 为客户端建立证书
[root@docker-node1 ~]# mkdir /etc/docker/certs.d/reg.exam.com/ -p
[root@docker-node1 ~]# cp /root/certs/exam.com.crt /etc/docker/certs.d/reg.exam.com/ca.crt
[root@docker-node1 ~]# systemctl restart docker
 
# 标签问题
[root@docker-node1 ~]# docker push reg.exam.com/busybox:latest
The push refers to repository [reg.exam.com/busybox]
An image does not exist locally with the tag: reg.exam.com/busybox
 
[root@docker-node1 ~]# docker tag busybox reg.exam.com/busybox:latest
[root@docker-node1 ~]# docker push reg.exam.com/busybox:latest
 
# DNS问题
[root@docker-node1 ~]# docker push reg.exam.com/busybox:latest
The push refers to repository [reg.exam.com/busybox]
Get "https://reg.exam.com/v2/": dial tcp: lookup reg.exam.com on 114.114.114.114:53: no such host
 
[root@docker-node1 ~]# vim /etc/hosts
The push refers to repository [reg.exam.com/busybox]
d51af96cf93e: Pushed 
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527
[root@docker-node1 ~]# 
 
# 测试
[root@docker-node1 ~]# curl -k https://reg.exam.com/v2/_catalog
{"repositories":["busybox"]}

4.4 为仓库建立登陆认证

bash 复制代码
# 安装建立认证文件的工具包
[root@docker-node1 ~]# dnf install httpd-tools -y
 
# 建立认证文件
[root@docker-node1 ~]# mkdir auth
[root@docker-node1 ~]# htpasswd -Bc auth/htpasswd lee    # -B 强制使用最安全加密方式,
默认用md5加密
New password: redhat	#密码
Re-type new password: 
Adding password for user lee
 
# 添加认证到registry容器中
[root@docker-node1 ~]# 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/exam.com.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/exam.com.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 certs]# curl -k https://reg.exam.com/v2/_catalog -u lee:redhat
{"repositories":["busybox"]}
 
# 登陆测试
[root@docker-node1 ~]# docker login reg.exam.com
Username: lee
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores
 
Login Succeeded

当仓库开启认证后必须登陆仓库才能进行镜像上传

bash 复制代码
# 未登陆情况下上传镜像
[root@docker ~]# docker push reg.timinglee.org/busybox
Using default tag: latest
The push refers to repository [reg.timinglee.org/busybox]
d51af96cf93e: Preparing
no basic auth credentials

# 未登陆情况下也不能下载
[root@docker-node2 ~]# docker pull reg.timinglee.org/busybox
Using default tag: latest
Error response from daemon: Head
"https://reg.timinglee.org/v2/busybox/manifests/latest": no basic auth
credentials

5 构建企业级私有仓库

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

Harbor 是由vmware公司开源的企业级 Docker Registry 项目。 它提供了以下主要功能和特点:

  1. 基于角色的访问控制(RBAC):可以为不同的用户和用户组分配不同的权限,增强了安全性和管理的灵活性。
  2. 镜像复制:支持在不同的 Harbor 实例之间复制镜像,方便在多个数据中心或环境中分发镜像。
  3. 图形化用户界面(UI):提供了直观的 Web 界面,便于管理镜像仓库、项目、用户等。
  4. 审计日志:记录了对镜像仓库的各种操作,有助于追踪和审查活动。
  5. 垃圾回收:可以清理不再使用的镜像,节省存储空间。

5.1 部署harbor

bash 复制代码
# 安装harbor
[root@docker-node1 ~]# tar zxf harbor-offline-installer-v2.5.4.tgz
[root@docker-node1 ~]# cd harbor/
[root@docker-node1 harbor]# ls
common.sh  harbor.v2.5.4.tar.gz  harbor.yml.tmpl  install.sh  LICENSE  prepare
[root@docker-node1 harbor]# cp harbor.yml.tmpl harbor.yml
 
# 建立认证并登录 
[root@docker-node1 ~]# htpasswd -Bc auth/htpasswd lee
 
# 创建加密密钥
[root@docker-node1 ~]# openssl req -newkey rsa:4096 \
-nodes -sha256 -keyout certs/exam.com.key \
-addext "subjectAltName = DNS:reg.exam.com" \
-x509 -days 365 -out certs/exam.com.crt
 
[root@docker-node1 ~]# mkdir /etc/docker/certs.d/reg.exam.com/ -p
[root@docker-node1 ~]# cp /root/certs/exam.com.crt /etc/docker/certs.d/reg.exam.com/ca.crt
[root@docker-node1 ~]# systemctl restart docker
 
# 修改配置文件
[root@docker-node1 harbor]# vim harbor.yml
 5 hostname: reg.exam.com
 17   certificate: /data/certs/exam.com.crt
 18   private_key: /data/certs/exam.com.key
 34 harbor_admin_password: redhat
[root@docker-node1 harbor]# mkdir /data
 
[root@docker-node1 data]# cp /root/certs /data/certs -r
 
[root@docker-node1 harbor]# ./install.sh --with-chartmuseum
 
[root@docker-node1 harbor]# docker compose stop
[root@docker-node1 harbor]# docker compose up -d

上传镜像

bash 复制代码
# 确保登录admin
[root@docker-node1 harbor]# docker login reg.exam.com
Authenticating with existing credentials...
Stored credentials invalid or expired
Username (lee): admin
Password: redhat
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores
 
Login Succeeded
 
# 打包镜像
[root@docker-node1 ~]# docker tag busybox:latest reg.exam.com/superlee/busybox:latest 
[root@docker-node1 ~]# docker push reg.exam.com/superlee/busybox:latest 
The push refers to repository 
 
# 上传镜像
[reg.exam.com/superlee/busybox]
d51af96cf93e: Pushed 
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527

五、 Docker 网络

docker的镜像是令人称道的地方,但网络功能还是相对薄弱的部分

docker安装后会自动创建3种网络:bridge、host、none

1 docker原生网络bridge

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

bash 复制代码
[root@docker mnt]# ip link show type bridge
  • bridge模式下容器没有一个公有ip,只有宿主机可以直接访问,外部主机是不可见的。
  • 容器通过宿主机的NAT规则后可以访问外网
bash 复制代码
# 更改内核参数
[root@docker-node1 ~]# grubby --update-kernel ALL --args iptables=true
[root@docker-node1 ~]# reboot
 
# 查看防火墙策略
[root@docker-node1 ~]# iptables -nL
 
# bridge
[root@docker-node1 harbor]# docker run -it --name webserver --network bridge busybox
/ # ifconfig 

2 docker原生网络host

host网络模式需要在容器创建时指定 --network=host host模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性

bash 复制代码
[root@docker-node1 ~]# docker run -d --name web -p 80:80 nginx:1.23
a1b8d4fa9c9bfd870c4997d295efb10ff155e50a4a1942d9c99fabe32a02de55
 
[root@docker-node1 ~]# ifconfig 

如果公用一个网络,那么所有的网络资源都是公用的,比如启动了nginx容器那么真实主机的80端口被占用,在启动第二个nginx容器就会失败

3 docker 原生网络none

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

bash 复制代码
[root@docker-node1 ~]# docker run -it --name test --rm --network none busybox
/ # ifconfig
lo              Link encap:Local Loopback
                inet addr:127.0.0.1 Mask:255.0.0.0
                inet6 addr: ::1/128 Scope:Host
                UP LOOPBACK RUNNING MTU:65536 Metric:1
                RX packets:0 errors:0 dropped:0 overruns:0 frame:0
                TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:1000
                RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

4 docker的自定义网络

自定义网络模式,docker提供了三种自定义网络驱动: bridge、overlay、macvlan

  • bridge驱动类似默认的bridge网络模式,但增加了一些新的功能
  • overlay和macvlan是用于创建跨主机网络

建议使用自定义的网络来控制哪些容器可以相互通信,还可以自动DNS解析容器名称到IP地址。

4.1 自定义桥接网络

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

bash 复制代码
[root@docker-node1 ~]# docker network create my_net1
 
[root@docker-node1 ~]# docker network ls
2644d485a93e   my_net1                     bridge    local

桥接默认是单调递增

bash 复制代码
[root@docker-node1 ~]# ifconfig

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

bash 复制代码
[root@docker-node1 ~]# docker network create my_net2 --subnet 172.25.0.0/24 --gateway 172.25.0.2
 
[root@docker-node1 ~]# docker network inspect my_net2 

4.2 为什么要自定义桥接

核心问题:默认bridge网络的缺陷

  1. Docker默认bridge网桥,容器IP是动态分配,分配规则取决于容器启动先后顺序。容器重启后IP可能发生变化。
  2. 如果直接用IP进行多容器互相访问,IP一变服务就不通,不可靠。
  3. Docker原生默认bridge网络不自带DNS解析,无法直接使用容器名称通信。

自定义桥接(自定义网络)的优势

内置DNS解析 :同一自定义网络内,可以直接使用容器名称互相访问,不用依赖IP,稳定性强。

注意:

  1. 不同自定义网络之间默认隔离,不能直接通讯。
  2. 底层防火墙:RHEL7 用iptables做网络隔离;RHEL9 使用nftables,可以用nft list ruleset查看隔离策略。

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

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

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

bash 复制代码
[root@docker-node1 ~]# docker run -d --name web1 --network my_net1 nginx
[root@docker-node1 ~]# docker run -it --name test --network my_net2 busybox
/ # ifconfig
eth0     Link encap:Ethernet HWaddr 02:42:C0:A8:00:01
         inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0
         UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
         RX packets:36 errors:0 dropped:0 overruns:0 frame:0
         TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
         collisions:0 txqueuelen:0
         RX bytes:5244 (5.1 KiB) TX bytes:0 (0.0 B)
lo       Link encap:Local Loopback
         inet addr:127.0.0.1 Mask:255.0.0.0
         inet6 addr: ::1/128 Scope:Host
         UP LOOPBACK RUNNING MTU:65536 Metric:1
         RX packets:0 errors:0 dropped:0 overruns:0 frame:0
         TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
         collisions:0 txqueuelen:1000
         RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2): 56 data bytes    #此时ping不通
 
[root@docker ~]# docker network connect my_net1 test
# 在上面test容器中加入网络eth1
/ # ifconfig
eth0     Link encap:Ethernet HWaddr 02:42:C0:A8:00:01
         inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0
         UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
         RX packets:45 errors:0 dropped:0 overruns:0 frame:0
         TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
         collisions:0 txqueuelen:0
         RX bytes:5879 (5.7 KiB) TX bytes:602 (602.0 B)
eth1     Link encap:Ethernet HWaddr 02:42:AC:12:00:03
         inet addr:172.18.0.3 Bcast:172.18.255.255 Mask:255.255.0.0
         UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
         RX packets:15 errors:0 dropped:0 overruns:0 frame:0
         TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
         collisions:0 txqueuelen:0
         RX bytes:2016 (1.9 KiB) TX bytes:0 (0.0 B)
lo       Link encap:Local Loopback
         inet addr:127.0.0.1 Mask:255.0.0.0
         inet6 addr: ::1/128 Scope:Host
         UP LOOPBACK RUNNING MTU:65536 Metric:1
         RX packets:4 errors:0 dropped:0 overruns:0 frame:0
         TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
         collisions:0 txqueuelen:1000
         RX bytes:212 (212.0 B) TX bytes:212 (212.0 B)

4.4 joined容器网络

Joined容器一种较为特别的网络模式,在容器创建时使用--network=container:vm1指定。(vm1指定的是运行的容器名)

处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用localhost高效快速通信。

bash 复制代码
[root@docker-node1 ~]# docker run -it --rm --name test --network mynet1 busybox
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:17 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:2330 (2.2 KiB)  TX bytes:0 (0.0 B)
 
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
 
/ # 
 
 
# 设置和test共用一个网卡
[root@docker-node1 ~]# docker run -it --name test1 --network container:test busybox  
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02  
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:19 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:2470 (2.4 KiB)  TX bytes:0 (0.0 B)
 
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

4.5 joined网络示例演示

利用容器部署phpmyadmin管理mysql

bash 复制代码
# 读取镜像
[root@docker-node1 ~]# docker load -i mysql-5.7.tar.gz
[root@docker-node1 ~]# docker load -i phpmyadmin-latest.tar.gz 
 
# 运行phpmysqladmin
[root@docker ~]# docker run -d --name mysqladmin --network my_net1 \
-e PMA_ARBITRARY=1 \             # 在web页面中可以手动输入数据库地址和端口
-p 80:80 phpmyadmin:latest
 
# 运行数据库
[root@docker ~]# docker run -d --name mysql \
-e MYSQL_ROOT_PASSWORD='redhat' \               # 设定数据库密码
--network container:mysqladmin \                # 把数据库容器添加到phpmyadmin容器中
mysql:5.7

开启的phpmyadmin容器中是没有数据库的

这里填写的localhost:3306是因为mysql容器和phpmyadmin容器公用一个网络站

5. 容器内外网的访问

5.1 容器访问外网

  • 在rhel7中,docker访问外网是通过iptables添加地址伪装策略来完成容器网文外网
  • 在rhel7之后的版本中通过nftables添加地址伪装来访问外网

5.2 外网访问docker容器

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

6 docker跨主机网络

在生产环境中,我们的容器不可能都在同一个系统中,所以需要容器具备跨主机通信的能力

跨主机网络解决方案:

  • docker原生的overlay和macvlan
  • 第三方的flannel、weave、calico

众多网络方案是如何与docker集成在一起的

  • libnetwork docker容器网络库
  • CNM (Container Network Model)这个模型对容器网络进行了抽象

6.1 CNM (Container Network Model)

CNM分三类组件

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

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

macvlan网络方式

  • Linux kernel提供的一种网卡虚拟化技术。
  • 无需Linux bridge,直接使用物理接口,性能极好
  • 容器的接口直接与主机网卡连接,无需NAT或端口映射。
  • macvlan会独占主机网卡,但可以使用vlan子接口实现多macvlan网络
  • vlan可以将物理二层网络划分为4094个逻辑网络,彼此隔离,vlan id取值为1~4094

macvlan网络间的隔离和连通

  • macvlan网络在二层上是隔离的,所以不同macvlan网络的容器是不能通信的
  • 可以在三层上通过网关将macvlan网络连通起来
  • docker本身不做任何限制,像传统vlan网络那样管理即可

示例:

bash 复制代码
# 在两台docker主机上各添加一块网卡,打开网卡混杂模式
[root@docker-node1 ~]# ip link set eth1 promisc on
[root@docker-node1 ~]# ip link set up eth1
[root@docker-node1 ~]# ifconfig eth1
eth1: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST>  mtu 1500
        ether 00:0c:29:ce:7a:46  txqueuelen 1000  (Ethernet)
        RX packets 75  bytes 4896 (4.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
         
# 添加macvlan网路
[root@docker-node1 ~]# docker network create \
> -d macvlan \
> --subnet 1.1.1.0/24 \
> --gateway 1.1.1.1 \
> -o parent=eth1 macvlan1
88995f57ffef146a45e2ceff0e22d73ab3b38385e485e93976f14ee0f260fd4b
 
[root@docker-node1 ~]# docker run -it --name busybox --network macvlan1 --ip 1.1.1.100 --rm busybox/ # 
 
/ # ping 1.1.1.200
PING 1.1.1.200 (1.1.1.200): 56 data bytes
64 bytes from 1.1.1.200: seq=0 ttl=64 time=1.038 ms
64 bytes from 1.1.1.200: seq=1 ttl=64 time=0.298 ms
64 bytes from 1.1.1.200: seq=2 ttl=64 time=0.354 ms
^C
--- 1.1.1.200 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.298/0.563/1.038 ms
/ # 
 
 
# node2
[root@docker-node2 ~]# docker load -i busybox-latest.tar.gz 
d51af96cf93e: Loading layer  4.495MB/4.495MB
Loaded image: busybox:latest
 
[root@docker-node2 ~]# docker run -it --name busybox --network macvlan1 --ip 1.1.1.200 --rm busybox/ # 
 
/ # ping 1.1.1.100
PING 1.1.1.100 (1.1.1.100): 56 data bytes
64 bytes from 1.1.1.100: seq=0 ttl=64 time=0.756 ms
^C
--- 1.1.1.100 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.756/0.756/0.756 ms

六、 Docker 数据卷管理及优化

Docker 数据卷是一个可供容器使用的特殊目录,它绕过了容器的文件系统,直接将数据存储在宿主机上

这样可以实现以下几个重要的目的:

  • 数据持久化:即使容器被删除或重新创建,数据卷中的数据仍然存在,不会丢失。
  • 数据共享:多个容器可以同时挂载同一个数据卷,实现数据的共享和交互。
  • 独立于容器生命周期:数据卷的生命周期独立于容器,不受容器的启动、停止和删除的影响

1 为什么要用数据卷

docker分层文件系统:性能差、生命周期与容器相同

docker数据卷

  • mount到主机中,绕开分层文件系统
  • 和主机磁盘性能相同,容器删除后依然保留
  • 仅限本地磁盘,不能随容器迁移

docker提供了两种卷: bind mount和docker managed volume

2 bind mount 数据卷

  • 是将主机上的目录或文件mount到容器里。
  • 使用直观高效,易于理解。
  • 使用 -v 选项指定路径格式 :
  • -v选项指定的路径,如果不存在,挂载时会自动创建
bash 复制代码
[root@docker-node1 ~]# docker run -it --rm \
> -v /tmp/data1:/data1 \
> -v /tmp/data1:/data2:ro \
> -v /etc/passwd:/data/passwd:ro busybox
/ # tail -n 3 /data/passwd 
tcpdump:x:72:72::/:/sbin/nologin
redhat:x:1000:1000:redhat:/home/redhat:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
/ # touch /data1/file1
/ # touch /data2/file1 
touch: /data2/file1: Read-only file system

3 docker managed 数据卷

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

示例:

bash 复制代码
[root@docker-node1 ~]# docker load -i mysql-5.7.tar.gz 
 
[root@docker-node1 ~]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='redhat' mysql:5.7 

[root@docker-node1 volumes]# ls -l /var/lib/docker/volumes/
 
[root@docker-node1 volumes]# touch 39e99109425ea3322d99b73c5672e6414eca041bbafcdee3c8476d74874f788e/_data/file
 
[root@docker-node1 volumes]# docker exec -it mysql bash
bash-4.2# cd /var/lib/mysql
bash-4.2# ls
auto.cnf    client-cert.pem  ib_buffer_pool  ibdata1  mysql.sock	  public_key.pem   sys
ca-key.pem  client-key.pem   ib_logfile0     ibtmp1   performance_schema  server-cert.pem
ca.pem	    file	     ib_logfile1     mysql    private_key.pem	  server-key.pem
bash-4.2# pwd
/var/lib/mysql
 
# 清理未使用的 Docker 数据卷
# [root@docker ~]# docker volume prune
 
# 建立数据卷
[root@docker-node1 ~]# docker volume create vol1
vol1
[root@docker-node1 ~]# ls -l /var/lib/docker/volumes/vol1/_data/
total 0
 
# 查看卷
[root@docker-node1 ~]# docker volume ls
local     vol1
 
# 使用建立的数据卷
[root@docker-node1 ~]# docker run -d --name web1 -p 80:80 -v vol1:/usr/share/nginx/html nginx
0ae5ae62f4c2d360731cb2106c7d6c9fadc28af491a05a406c7c1e5380576023
[root@docker-node1 ~]# cd /var/lib/docker/volumes/vol1/_data/
[root@docker-node1 _data]# ls
50x.html  index.html
[root@docker-node1 _data]# echo vol1 > index.html 
[root@docker-node1 _data]# curl 172.25.250.100
vol1

4 数据卷容器(Data Volume Container)

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

bash 复制代码
# 建立数据卷容器
[root@docker-node1 ~]# docker run -d --name datavol \
> -v /tmp/data1/:/data1:rw \
> -v /tmp/data2/:/data2:ro \
> -v /etc/resolv.conf:/etc/hosts busybox
 
# 使用数据卷容器
[root@docker-node1 ~]# docker run -it --name test --rm --volumes-from datavol busybox
/ # ls
bin    data1  data2  dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var
/ # cat /etc/resolv.conf 
# Generated by Docker Engine.
# This file can be edited; Docker Engine will not make further changes once it
# has been modified.
 
nameserver 114.114.114.114
search exam.com
 
# Based on host file: '/etc/resolv.conf' (legacy)
# Overrides: []
/ # touch data1/file1 
/ # touch data2/file1 
touch: data2/file1: Read-only file system
/ # 

5 bind mount 数据卷和docker managed 数据卷的对比

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

不同点:

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

6 备份与迁移数据卷

bash 复制代码
# 备份数据卷
# 建立容器并指定使用卷到要备份的容器
[root@docker ~]# docker run --volumes-from datavol \
-v `pwd`:/backup busybox \ # 把当前目录挂在到容器中用于和容器交互保存要备份的容器
tar zcf /backup/data1.tar.gz /data1 # 备份数据到本地

# 数据恢复
docker run -it --name test -v leevol1:/data1 -v `pwd`:/backup busybox /bin/sh -c "tar zxf /backup/data1.tar.gz;/bin/sh"
/ # ls
backup data1 etc lib proc sys usr
bin dev home lib64 root tmp var
/ # cd data1/ # 查看数据迁移情况
/data1 # ls
index.html file1

七、 Docker 的安全优化

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

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

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

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

root@docker \~# grubby --update-kernel=/boot/vmlinuz-$(uname -r) \

--args="systemd.unified_cgroup_hierarchy=0

systemd.legacy_systemd_cgroup_controller"

1 命名空间隔离的安全

  • 当docker run启动一个容器时,Docker将在后台为容器创建一个独立的命名空间。命名空间提供了 最基础也最直接的隔离。
  • 与虚拟机方式相比,通过Linux namespace来实现的隔离不是那么彻底。
  • 容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作 系统内核。
  • 在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,比如:磁盘等等
bash 复制代码
[root@docker-node1 ~]# mount -t cgroup
[root@docker-node1 ~]# mount -t cgroup2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot)
 
 
grubby --update-kernel=/boot/vmlinuz-$(uname -r) \
--args="systemd.unified_cgroup_hierarchy=0 systemd.legacy_systemd_cgroup_controller"
reboot
 
[root@docker-node1 ~]# docker run -d --name web nginx
[root@docker-node1 ~]# docker inspect web | grep Pid
[root@docker-node1 ~]# cd /proc/4678/ns/
[root@docker-node1 ns]# ls
cgroup  ipc  mnt  net  pid  pid_for_children  time  time_for_children  user  uts
[root@docker-node1 ns]# ls -d 

2 控制组资源控制的安全

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

/ # free -m
              total        used        free      shared  buff/cache   available
Mem:           1743         396         834           6         513        1194
Swap:          4096           0        4096
/ # exit
[root@docker-node1 ~]# free -m
               total        used        free      shared  buff/cache   available
Mem:            1743         512         870           6         514        1231
Swap:           4095           0        4095

3 内核能力机制

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

4 Docker服务端防护

  • 使用Docker容器的核心是Docker服务端,确保只有可信的用户才能访问到Docker服务。
  • 将容器的root用户映射到本地主机上的非root用户,减轻容器和主机之间因权限提升而引起的安全 问题。
  • 允许Docker 服务端在非root权限下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。 这些子进程只允许在特定范围内进行操作。
bash 复制代码
[root@docker-node1 ~]# ls -ld /var/lib/docker/ # 默认docker是用root用户控制资源的

1 Docker的资源限制

Linux Cgroups 的全称是 Linux Control Group。

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

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

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

在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。

在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录)。

控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定。

1.1.限制cpu使用

1.限制cpu的使用量

bash 复制代码
[root@docker-node1 ~]# docker load -i ubuntu-latest.tar.gz 
f36fd4bb7334: Loading layer  80.56MB/80.56MB
Loaded image: ubuntu:latest
 
[root@docker-node1 ~]# docker run -it --rm --name test \
> --cpu-period 100000 \
> --cpu-quota 20000 ubuntu
 
root@59bb8bdc0225:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@59bb8bdc0225:/# top
top - 07:13:26 up 20 min,  0 user,  load average: 0.97, 0.51, 0.21
Tasks:   3 total,   2 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.7 us,  2.0 sy,  0.0 ni, 96.9 id,  0.0 wa,  0.2 hi,  0.2 si,  0.0 st 
MiB Mem :   1743.5 total,    668.4 free,    550.4 used,    682.0 buff/cache     
MiB Swap:   4096.0 total,   4096.0 free,      0.0 used.   1193.1 avail Mem 
 
    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                    
      9 root      20   0    2736   1408   1408 R  19.7   0.1   0:09.68 dd                         
      1 root      20   0    4588   3712   3200 S   0.0   0.2   0:00.01 bash                       
     10 root      20   0    8848   5120   3072 R   0.0   0.3   0:00.00 top
     
# 在cgroup中查看docker的资源限制
[root@docker ~]# cat /sys/fs/cgroup/system.slice/docker573150b6c2c90a53f9d75df77455a526ff14e93fb7304674c80307c51882e605.scope/cpu.max 20000 100000

2.限制cpu的优先级

bash 复制代码
# 关闭cpu的核心,当cpu都不空闲下才会出现争抢的情况,为了实验效果我们可以关闭一个cpu核心
[root@docker-node1 ~]# echo 0 > /sys/devices/system/cpu/cpu1/online 
 
[root@docker-node1 ~]# cat /proc/cpuinfo 
 
[root@docker-node1 ~]# docker run -it --rm --cpu-shares 100 ubuntu
root@5ecafc581a63:/# dd if=/dev/zero of=/dev/null &
[1] 9
root@5ecafc581a63:/# top

1.2 限制内存使用

bash 复制代码
# 安装依赖性
libcgroup-0.41-19.el8.x86_64.rpm
libcgroup-tools-0.41-19.el8.x86_64.rpm
 
# 开启容器并限制容器使用内存大小
[root@docker-node1 ~]# docker run -d --name test --memory 200M --memory-swap 200M nginx
6010d0618fb82d8687b3d15179537a3fadc746bce745f816514f59c7122d1166
 
# 查看容器内存使用限制
[root@docker-node1 ~]# cd /sys/fs/cgroup/memory/docker/6010d0618fb82d8687b3d15179537a3fadc746bce745f816514f59c7122d1166/
[root@docker-node1 6010d0618fb82d8687b3d15179537a3fadc746bce745f816514f59c7122d1166]# cat memory.limit_in_bytes 
209715200
[root@docker-node1 6010d0618fb82d8687b3d15179537a3fadc746bce745f816514f59c7122d1166]# cat memory.memsw.limit_in_bytes 
209715200
 
# 测试容器内存限制,在容器中我们测试内存限制效果不是很明显,可以利用工具模拟容器在内存中写入数据
# 在系统中/dev/shm这个目录被挂在到内存中
[root@docker-node1 ~]# docker run -d --name test --memory 200M --memory-swap 200M nginx
415ee962d70e40bdac774b2869d5e4d6faa13479bd74608e7b1618e9d46327ee
 
[root@docker-node1 ~]# cgexec -g memory:docker/415ee962d70e40bdac774b2869d5e4d6faa13479bd74608e7b1618e9d46327ee dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=150
150+0 records in
150+0 records out
157286400 bytes (157 MB, 150 MiB) copied, 0.53283 s, 295 MB/s
[root@docker-node1 ~]# cgexec -g memory:docker/415ee962d70e40bdac774b2869d5e4d6faa13479bd74608e7b1618e9d46327ee dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=120
120+0 records in
120+0 records out
125829120 bytes (126 MB, 120 MiB) copied, 0.0695907 s, 1.8 GB/s
[root@docker-node1 ~]# cgexec -g memory:docker/415ee962d70e40bdac774b2869d5e4d6faa13479bd74608e7b1618e9d46327ee dd if=/dev/zero of=/dev/shm/bigfile bs=1M count=200
Killed
[root@docker-node1 ~]# 

1.3 限制docker的磁盘io

bash 复制代码
[root@docker-node1 ~]# docker run -it --rm \
--device-write-bps \			# 指定容器使用磁盘io的速率
/dev/nvme0n1:30M \				# /dev/nvme0n1是指定系统的磁盘,30M即每秒30M数据
ubuntu
 
root@149e8aba1b2f:/# dd if=/dev/zero of=bigfile	# 开启容器后会发现速度和设定不匹配,是因为系统的缓存机制
^C1576748+0 records in
1576748+0 records out
807294976 bytes (807 MB, 770 MiB) copied, 5.85982 s, 138 MB/s
 
root@149e8aba1b2f:/# dd if=/dev/zero of=/bigfile bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.0558805 s, 1.9 GB/s
 
root@149e8aba1b2f:/# dd if=/dev/zero of=bigfile bs=1M count=100 oflag=direct # 设定dd命令直接写入磁盘
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 3.33922 s, 31.4 MB/s

2 Docker的安全加固

2.1 Docker默认隔离性

在系统中运行容器,我们会发现资源并没有完全隔离开

bash 复制代码
[root@docker-node1 ~]# free -m
# 系统内存使用情况
              total        used        free      shared  buff/cache   available
Mem:           3627        1128        1714         207        1238        2498
Swap:          2062           0        2062

[root@docker-node1 ~]# docker run --rm --memory 200M -it ubuntu
root@e06bdc13b764:/# free -m
# 容器中内存使用情况
              total        used        free      shared  buff/cache   available
Mem:           3627        1211        1630         207        1239        2415
Swap:          2062           0        2062

# 虽然我们限制了容器的内存使用情况,但是查看到的信息依然是系统中内存的使用信息,并没有隔离开

2.2 解决Docker的默认隔离性

LXCFS 是一个为 LXC(Linux Containers)容器提供增强文件系统功能的工具。

主要功能:

  1. 资源可见性: LXCFS 可以使容器内的进程看到准确的 CPU、内存和磁盘 I/O 等资源使用信息。在没有 LXCFS 时,容器内看到的资源信息可能不准确,这会影响到在容器内运行的应用程序对资源的评估和 管理。
  2. 性能监控: 方便对容器内的资源使用情况进行监控和性能分析。通过提供准确的资源信息,管理员和开发 人员可以更好地了解容器化应用的性能瓶颈,并进行相应的优化。
bash 复制代码
# 在rhe19中lxcfs是被包含在epel源中,我们可以直接下载安装包进行安装
[root@docker-node1 ~]# ls lxcfs
lxcfs-5.0.4-1.el9.x86_64.rpm  lxc-libs-4.0.12-1.el9.x86_64.rpm  lxc-templates-4.0.12-1.el9.x86_64.rpm

[root@docker-node1 ~]# dnf install lxcfs/*.rpm

# 运行lxcfs并解决容器隔离性
[root@docker-node1 ~]# lxcfs /var/lib/lxcfs &
[root@docker-node1 ~]# docker run  -it -m 256m \
-v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw \
-v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw \
-v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw \
-v /var/lib/lxcfs/proc/stat:/proc/stat:rw \
-v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \
-v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw \
ubuntu

root@69ec0c67ff04:/# free -m
              total        used        free      shared  buff/cache   available
Mem:           256           1         254           0           0         254
Swap:          512           0         512

2.3 容器特权

在容器中默认情况下即使我是容器的超级用户也无法修改某些系统设定,比如网络

bash 复制代码
[root@docker-node1 ~]# docker run --rm -it busybox
/ # whoami
root
/ # ip a

这是因为容器使用的很多资源都是和系统真实主机公用的,如果允许容器修改这些重要资源,系统的稳定性会变的非常差

但是由于某些需要求,容器需要控制一些默认控制不了的资源,如何解决此问题,这时我们就要设置容器特权

bash 复制代码
[root@docker ~]# docker run --rm -it --privileged busybox
/ # id root
uid=0(root) gid=0(root) groups=0(root),10(wheel)
/ # ip a a 192.168.0.100/24 dev eth0
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
29: eth0@if30: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 192.168.0.100/24 scope global eth0
       valid_lft forever preferred_lft forever

/ # fdisk -l
Disk /dev/nvme0n1: 100 GB, 107374182400 bytes, 209715200 sectors
13003 cylinders, 256 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device        Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/nvme0n1p1    0,0,2       1023,255,63           1 209715199 209715199 99.9G ee EFI GPT

# 如果添加了--privileged 参数开启容器,容器获得权限近乎于宿主机的root用户

2.4 容器特权的白名单

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

capabilities手册地址:http://man7.org/linux/man-pages/man7/capabilities.7.html

bash 复制代码
# 限制容器对网络有root权限
[root@docker-node1 ~]# docker run --rm -it --cap-add NET_ADMIN busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
72: eth0@if32: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # ip a a 1.1.1.1/24 dev eth0		# 网络可以设定
/ # fdisk -l						# 无法管理磁盘
 
/ # 

八、 容器编排工具Docker Compose

1 Docker Compose 概述

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

其是官方的一个开源项目,托管到github上

网址:https://github.com/docker/compose

主要功能

  1. 定义服务: 使用 YAML 格式的配置文件来定义一组相关的容器服务。每个服务可以指定镜像、端口映射、环境变量、存储卷等参数。 例如,可以在配置文件中定义一个 Web 服务和一个数据库服务,以及它们之间的连接关系。
  2. 一键启动和停止: 通过一个简单的命令,可以启动或停止整个应用程序所包含的所有容器。这大大简化了多容器应用的部署和管理过程。 例如,使用 docker-compose up 命令可以启动配置文件中定义的所有服务,使用 docker-compose down 命令可以停止并删除这些服务。
  3. 服务编排: 可以定义容器之间的依赖关系,确保服务按照正确的顺序启动和停止。例如,可以指定数据库服务必须在 Web 服务之前启动。 支持网络配置,使不同服务的容器可以相互通信。可以定义一个自定义的网络,将所有相关的容器连接到这个网络上。
  4. 环境变量管理: 可以在配置文件中定义环境变量,并在容器启动时传递给容器。这使得在不同环境(如开发、测试和生产环境)中使用不同的配置变得更加容易。 例如,可以定义一个数据库连接字符串的环境变量,在不同环境中可以设置不同的值。

工作原理

  1. 读取配置文件: Docker Compose 读取 YAML 配置文件,解析其中定义的服务和参数。
  2. 创建容器: 根据配置文件中的定义,Docker Compose 调用 Docker 引擎创建相应的容器。它会下载所需 的镜像(如果本地没有),并设置容器的各种参数。
  3. 管理容器生命周期: Docker Compose 监控容器的状态,并在需要时启动、停止、重启容器。 它还可以处理容器的故障恢复,例如自动重启失败的容器。

Docker Compose 中的管理层

  1. 服务 (service) 一个应用的容器,实际上可以包括若干运行相同镜像的容器实例
  2. 项目 (project) 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中 定义
  3. 容器(container)容器是服务的具体实例,每个服务可以有一个或多个容器。容器是基于服务定义 的镜像创建的运行实例

2 Docker Compose 的常用命令参数

bash 复制代码
[root@docker-node1 ~]# vim docker/docker-compose.yml 
 
services:
  web:
    image: nginx
    ports:
      - "80:80"
 
  db: 
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: redhat
 
# 服务管理
启动
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# docker compose up -d
[+] Running 2/2
 ✔ Container docker-db-1   Running                                                             0.0s 
 ✔ Container docker-web-1  Started                                                             0.4s
 
 [root@docker-node1 ~]# docker compose -f docker/docker-compose.yml up -d
[+] Running 2/0
 ✔ Container docker-db-1   Running                                                             0.0s 
 ✔ Container docker-web-1  Running                                                             0.0s

2.1 服务管理

  1. docker-compose up :
  • 启动配置文件中定义的所有服务。
  • 可以使用 -d 参数在后台启动服务。
  • 可以使用-f 来指定yml文件 例如: docker-compose up -d 。
bash 复制代码
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# docker compose up -d
[+] Running 2/2
 ✔ Container docker-db-1     Running                                                    0.0s
 ✔ Container docker-web-1    Started                                                    0.4s
[root@docker-node1 docker]# cd
[root@docker-node1 ~]# 
[root@docker-node1 ~]# docker compose -f docker/docker-compose.yml up -d
[+] Running 2/0
 ✔ Container docker-db-1     Running                                                    0.0s
 ✔ Container docker-web-1    Running                                                    0.0s
  1. docker-compose down : 停止并删除配置文件中定义的所有服务以及相关的网络和存储卷。
bash 复制代码
[root@docker-node1 ~]# docker compose -f docker/docker-compose.yml down 
[+] Running 3/3
 ? Container docker-db-1   Removed                                                             1.1s 
 ? Container docker-web-1  Removed                                                             0.1s 
 ? Network docker_default  Removed                                                             0.1s
  1. docker-compose start : 启动已经存在的服务,但不会创建新的服务。
bash 复制代码
[root@docker-node1 docker]# docker compose start 
[+] Running 2/2
 ✔ Container docker-web-1  Started                                                             0.4s 
 ✔ Container docker-db-1   Started                                                             0.3s
  1. docker-compose stop : 停止正在运行的服务
bash 复制代码
[root@docker-node1 docker]# docker compose stop
[+] Stopping 2/2
 ✔ Container docker-web-1  Stopped                                                             0.2s 
 ✔ Container docker-db-1   Stopped                                                            10.1s
  1. docker-compose restart : 重启服务。
bash 复制代码
[root@docker-node1 docker]# docker compose restart

2.2 服务状态查看

  1. docker-compose ps :列出正在运行的服务以及它们的状态,包括容器 ID、名称、端口映射等信息
bash 复制代码
[root@docker-node1 ~]# docker compose -f docker/docker-compose.yml ps
NAME           IMAGE       COMMAND                  SERVICE   CREATED         STATUS              PORTS
docker-db-1    mysql:5.7   "docker-entrypoint.s."   db        3 minutes ago   Up 3 minutes        3306/tcp, 33060/tcp
docker-web-1   nginx       "/docker-entrypoint.¡."   web       3 minutes ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp
  1. docker-compose logs : 查看服务的日志输出。可以指定服务名称来查看特定服务的日志。
bash 复制代码
[root@docker-node1 docker]# docker compose logs db

2.3 构建和重新构建服务(了解)

  1. docker-compose build : 构建配置文件中定义的服务的镜像。可以指定服务名称来只构建特定的服务。

  2. docker-compose up --build : 启动服务并在启动前重新构建镜像。

2.4 其他操作

  1. docker-compose exec : 在正在运行的服务容器中执行命令。
bash 复制代码
# test.yml
services:
  test:
    image: busybox
    command: ["/bin/sh","-c","sleep 3000"]
    restart: always
    container_name: busybox1

[root@docker-node1 test]# docker compose -f test.yml up -d
[root@docker-node1 test]# docker compose -f test.yml exec test sh
/ #
  1. docker-compose pull : 拉取配置文件中定义的服务所使用的镜像。
bash 复制代码
[root@docker-node1 test]# docker compose -f test.yml pull
[+] Pulling 2/2
 ✔ test Pulled
 ✔ ec562eabd705 Pull complete
  1. docker-compose config : 验证并查看解析后的 Compose 文件内容
bash 复制代码
[root@docker-node1 test]# docker compose -f test.yml config
name: test
services:
  test:
    command:
      - /bin/sh
      - -c
      - sleep 3000
    container_name: busybox1
    image: busybox
    networks:
      default: null
    restart: always
networks:
  default:
    name: test_default
[root@docker-node1 test]# docker compose -f test.yml config -q

3 Docker Compose 的yml文件

Docker Compose 的 YAML 文件用于定义和配置多容器应用程序的各个服务。以下是一个基本的 Docker Compose YAML 文件结构及内容解释:

3.1 服务(services)

  1. 服务名称(service1_name/service2_name 等): 每个服务在配置文件中都有一个唯一的名称,用于在命令行和其他部分引用该服务。
bash 复制代码
services:
 web:
   # 服务1的配置
 mysql:
   # 服务2的配置
  1. 镜像(image): 指定服务所使用的 Docker 镜像名称和标签。例如, image: nginx:latest 表示使用 nginx 镜像的最新版本
bash 复制代码
services:
 web:
   images:nginx
 mysql:
   images:mysql:5.7
  1. 端口映射(ports): 将容器内部的端口映射到主机的端口,以便外部可以访问容器内的服务。例如, - "8080:80" 表示将主机的 8080 端口映射到容器内部的 80 端口。
bash 复制代码
services:
 web:
   image: superhowe/mario
   container_name: game # 指定容器名称
    restart: always   # docekr容器自动启动
   expose:
   - 1234 # 指定容器暴露那些端口,些端口仅对链接的服务可见,不会映射到主机的端口
   ports:
      - "80:8080"
  1. 环境变量(environment): 为容器设置环境变量,可以在容器内部的应用程序中使用。例如, VAR1: value1 设置环境变 量 VAR1 的值为 value1
bash 复制代码
services:
  web:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: redhat
  1. 存储卷(volumes): 将主机上的目录或文件挂载到容器中,以实现数据持久化或共享。例如, - /host/data:/container/data 将主机上的 /host/data 目录挂载到容器内的 /container/data 路径。
bash 复制代码
services:
  web:
    image: busybox
    command: ["/bin/sh","-c","sleep 100000"]
    container_name: busybox1
    volumes: 
      - /etc/passwd:/tmp/passwd:ro        # 只读挂在本地文件到指定位置
  1. 网络(networks): 将服务连接到特定的网络,以便不同服务的容器可以相互通信
bash 复制代码
services:
  web:
    image: nginx
    container_name: webserver
    network_mode: bridge # 使用本机自带bridge网络
services:
  test:
    image: busybox 
    container_name: webserver
    command: ["/bin/sh","-c","sleep10000000"]
 
  networks:
    - mynet1
    - mynet2
 
  networks:
    mynet1:
      driver: bridge
    mynet2:
      driver: bridge
  1. 命令(command): 覆盖容器启动时默认执行的命令。例如, command: python app.py 指定容器启动时运行 python app.py 命令
bash 复制代码
services:
 web:
   image: busybox
   container_name: busybox
   #network_mode: mynet2
   command: ["/bin/sh","-c","sleep10000000"]

3.2 网络(networks)

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

bash 复制代码
services:
  test1:
    image: busybox:latest
    command: ["/bin/sh","-c","sleep 10000"]
    network_mode: default
    container_name: test
 
  test2:
    image: busybox:latest
    command: ["/bin/sh","-c","sleep 100000"]
    container_name: test2
    networks:
      - mynet1
      - mynet2
 
networks:
  default:
    external: true
    name: bridge
 
  mynet1:
    driver: brige
 
  mynet2:
    ipam:
      driver: default
      config:
        - subnet: 172.26.0.0/24
          gateway: 172.26.0.2
         
 
[root@docker-node1 test]# docker compose up -d

3.3 存储卷(volumes)

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

bash 复制代码
services:
  test1:
    image: busybox:latest
    command: ["/bin/sh","-c","sleep 10000"]
    network_mode: default
    container_name: test
 
  test2:
    image: busybox:latest
    command: ["/bin/sh","-c","sleep 100000"]
    container_name: test2
    networks:
      - mynet1
      - mynet2
    volumes: 
      - data:/data			# 挂在data卷
 
networks:
  default:
    external: true
    name: bridge
 
  mynet1:
    driver: bridge
 
  mynet2:
    ipam:
      driver: default
      config:
        - subnet: 172.26.0.0/24
          gateway: 172.26.0.2
 
  volumes:
    data:
      name: howe		# 指定建立卷的名字
 
 
# 检测语法错误
docker compose config 
docker compose config -q # 不打印错误

4 企业示例

利用容器编排完成haproxy和nginx负载均衡架构实施

bash 复制代码
[root@docker-node1 ~]# yum install haproxy -y --downloadonly --downloaddir=/mnt
[root@docker-node1 test]# cd /mnt/
[root@docker-node1 mnt]# ls
haproxy-2.4.22-3.el9_3.x86_64.rpm  hgfs
[root@docker-node1 mnt]# rpm2cpio haproxy-2.4.22-3.el9_3.x86_64.rpm | cpio -id
13488 blocks
[root@docker-node1 mnt]# ls
etc  haproxy-2.4.22-3.el9_3.x86_64.rpm  hgfs  usr  var
[root@docker-node1 mnt]# cd etc/
[root@docker-node1 etc]# ls
haproxy  logrotate.d  sysconfig
[root@docker-node1 etc]# cd haproxy/
[root@docker-node1 haproxy]# ls
conf.d  haproxy.cfg
 
[root@docker-node1 haproxy]# mkdir /var//lib/docker/volumes/conf
[root@docker-node1 haproxy]# cp haproxy.cfg /var/lib/docker/volumes/conf/
[root@docker-node1 haproxy]# cd /var/lib/docker/volumes/conf/
[root@docker-node1 conf]# ls
haproxy.cfg
[root@docker-node1 conf]# vim haproxy.cfg 
...
listen webcluter
  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-node1 ~]# cd test/
[root@docker-node1 test]# ls
docker-compose.yml
[root@docker-node1 test]# vim docker-compose.yml 
[root@docker-node1 test]# cat docker-compose.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
    restart: always
    container_name: haproxy
    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

[root@docker-node1 test]# docker compose -f docker-compose.yml up -d
[+] Running 5/5
✔ Network test_mynet1 Created
0.1s
✔ Network test_mynet2 Created
0.1s
✔ Container haproxy Started
0.8s
✔ Container web1 Started
0.7s
✔ Container web2 Started
0.6s
 
[root@docker-node1 test]# docker compose -f haproxy.yml up -d
[+] Running 7/7
 ✔ Network test_internel  Created                                                                                                                                     0.1s 
 ✔ Network test_extrnal   Created                                                                                                                                     0.1s 
 ✔ Volume "data_web2"     Created                                                                                                                                     0.0s 
 ✔ Volume "data_web1"     Created                                                                                                                                     0.0s 
 ✔ Container haproxy      Started                                                                                                                                     1.2s 
 ✔ Container webserver1   Started                                                                                                                                     1.2s 
 ✔ Container webserver2   Started                                                                                                                                     1.1s 
[root@docker-node1 test]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                               NAMES
7158668dd70f   nginx:latest   "/docker-entrypoint...."   7 seconds ago   Up 6 seconds   80/tcp                              webserver2
8aa9a99597df   haproxy:2.3    "docker-entrypoint.s..."   7 seconds ago   Up 6 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   haproxy
d5f6b242b8e1   nginx:latest   "/docker-entrypoint...."   7 seconds ago   Up 6 seconds   80/tcp                              webserver1
 
 
# 写入内容并测试:
[root@docker-node1 test]# echo webserver1 > /var/lib/docker/volumes/data_web1/_data/index.html
[root@docker-node2 test]# echo webserver2 > /var/lib/docker/volumes/data_web2/_data/index.html
 
[root@docker-node1 test]# curl 172.25.250.200
webserver2
[root@docker-node1 test]# curl 172.25.250.200
webserver1
[root@docker-node1 test]# curl 172.25.250.200
webserver2
[root@docker-node1 test]# curl 172.25.250.200
webserver1
相关推荐
java_logo4 小时前
Docker 部署 MariaDB:轻松搭建开源关系型数据库
数据库·docker·容器·开源·mariadb·轩辕镜像·docker部署教程
池佳齐4 小时前
【软考高级架构师案例】容器化改造:Docker + K8s,如何用云原生视角重构传统多层架构?
docker·云原生·kubernetes
zh73144 小时前
Docker Desktop on Windows 挂载问题根因分析
windows·docker·容器
Brilliantee4045 小时前
docker迁移SOP
docker·容器·eureka
kuroomi5 小时前
K8s集群升级与etcd备份恢复实战
容器·kubernetes·etcd
大盛供应链·卢生6 小时前
半导体行业发展的主要驱动力,到底是什么?
容器·新浪微博
川石课堂软件测试6 小时前
自动化测试|持续集成Git使用详解
git·python·jmeter·mysql·ci/cd·容器·kubernetes
探索云原生7 小时前
KServe 工作流程:从 InferenceService 到 vLLM 服务
docker·ai·云原生·kubernetes·go
剑锋所指,所向披靡!7 小时前
Docker基础
运维·docker·容器