Docker(完整实验版)

一 Docker简介

1.1 Docker简介

1.1.1 什么是docker?

Docker是管理容器的引擎,为应用打包、部署平台,而非单纯的虚拟化技术 它具有以下几个重要特点和优势:

1. 轻量级虚拟化:

  • Docker 容器相较于传统的虚拟机更加轻量和高效,能够快速启动和停止,节省系统资源。例如,启动一个 Docker 容器可能只需要几秒钟,而启动一个虚拟机则可能需要几分钟。

2. 一致性

  • 确保应用程序在不同的环境中(如开发、测试、生产)具有一致的运行表现。无论在本地还是云端,应用的运行环境都能保持相同,减少了因环境差异导致的问题。

3. 可移植性

  • 可以轻松地将 Docker 容器从一个平台迁移到另一个平台,无需担心依赖和环境配置的差异。比如,在本地开发的容器可以无缝部署到云服务器上。

4. 高效的资源利用

  • 多个 Docker容器可以共享主机的操作系统内核,从而更有效地利用系统资源。

5. 易于部署和扩展

  • 能够快速部署新的应用实例,并且可以根据需求轻松地进行水平扩展。总之,Docker 极大地简化了应用程序的开发、部署和管理流程,提高了开发效率和运维的便利性。它在现代软件开发和云计算领域得到了广泛的应用。

1.1.2 docker在企业中的应用场景

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

1.1.3 docker与虚拟化的对比

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

1.1.4 docker的优势

一、轻量级和高效性

  • 资源占用少
  • 快速启动和停止

二、可移植性和一致性

  • 跨平台部署
  • 环境一致性

三、简化开发和部署流程

  • 开发环境一致性
  • 持续集成和持续部署(CI/CD)

四、隔离性和安全性

  • 进程隔离
  • 安全沙箱

五、弹性和扩展性

  • 快速扩展
  • 动态调整资源

1.2 部署docker

容器工作方法

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

1.2.1 配置软件仓库 

虚拟机环境 redhat9

#配置软件仓库
[root@docker-node1 ~]# vim /etc/yum.repos.d/docker-ce.repo 
[docker]
name=docker-ce
baseurl=https://mirrors.aliyun.com/docker-ce/linux/rhel/9/x86_64/stable/
gpgcheck=0

#安装docker-ce并启动服务
[root@k8s ~]# tar zxf docker.tar.gz 
[root@k8s ~]# dnf install *.rpm -y

[root@docker-node1 ~]# systemctl enable --now docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.

#加速器
1. https://3tax6oij.mirror.aliyuncs.com
2. https://docker.m.daocloud.io

[root@k8s docker]# vim /etc/docker/daemon.json
{
  "registry-mirrors": ["https://docker.m.daocloud.io"]
}

[root@k8s ~]# systemctl daemon-reload 
[root@k8s ~]# systemctl restart docker


#读取镜像
[root@docker-node1 ~]# docker load -i busybox-latest.tar.gz 
d51af96cf93e: Loading layer  4.495MB/4.495MB
Loaded image: busybox:latest


#运行容器
[root@docker-node1 ~]# docker run -d --rm --name game2 -p 80:80 timinglee/game2048:latest
376f05756eaec07badec71ae04fec4e499fe60d5433bbf8b41d0830aa6707f50

在rhel7中 需要激活内核网络

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

sysctl --system
systemctl restart docker

二 Docker的基本操作

2.1 Docker镜像管理

2.1.1 搜索镜像

#以nginx为例
[root@docker-node1 ~]# docker search nginx
参数说明
NAME镜像名称
DESCRIPTION镜像说明
STARS点赞数量
OFFICIAL是否是官方的

2.1.2 拉取镜像

#从镜像仓库中拉取镜像
[root@docker-node1 ~]# docker pull busybox
[root@docker-node1 ~]# docker pull nginx:1.26-alpine        #alpine 版本:nginx镜像的最小安装发型版本


#查看本地镜像
[root@docker-node1 ~]# docker images

2.1.3 查看镜像信息

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

2.1.4 导出镜像

#保存镜像
[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 可以导出并压缩

2.1.5 删除镜像

[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 容器的常用操作

2.2.1 启动容器

[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.2 查看容器运行信息

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

2.2.3 停止和运行容器

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

2.2.4 删除容器

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

2.2.5 容器内容提交

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

[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
nginx                1.26-alpine   9703b2608a98   12 days ago     43.3MB
nginx                latest        5ef79149e0ec   12 days ago     188MB
busybox              latest        65ad0d468eb1   15 months ago   4.26MB
timinglee/game2048   latest        19299002fdbe   7 years ago     55.5MB
timinglee/mario      latest        9a35a9e43e8c   8 years ago     198MB


[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    
Note:此方法不利于企业审计,所以不推荐使用,在企业中我们多用Dockerfile来构建镜像

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

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

#把本机文件复制到容器中
[root@docker-node1 ~]# docker cp /etc/fstab test2:/fstab     

2.2.7 查询容器内部日志

[root@docker-node1 ~]# docker logs

三 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 构建参数

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功能和用法类似,但动作不可被覆盖

 示例:

[root@docker-node1 ~]# mkdir docker/
[root@docker-node1 ~]# cd docker/
[root@docker-node1 docker]# touch file 
[root@docker-node1 docker]# vim Dockerfile 
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest				#指定使用的基础镜像
MAINTAINER howe@exam.com		#指定作者信息
COPY file /						#复制当前目录文件到容器指定位置,leefile必须在当前目录中

[root@docker-node1 docker]# docker build -t example:v1 .		#构建镜像

[root@docker-node1 docker]# docker build -t example:v1 .^C
[root@docker-node1 docker]# touch file{1..3}
[root@docker-node1 docker]# tar zcf file.gz file*
[root@docker-node1 docker]# vim Dockerfile 
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
MAINTAINER howe@exam.com
COPY file /
ADD file.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


#CMD1
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
MAINTAINER howe@exam.com
ENV NAME howe
CMD echo $NAME

[root@docker-node1 docker]# docker build -t example:v3 .

[root@docker-node1 docker]# docker run -it --rm --name test example:v3
howe

#CMD2
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
MAINTAINER howe@exam.com
ENV NAME howe
#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
$NAME
[root@docker-node1 docker]# docker rmi example:v3 

#CMD3
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
MAINTAINER howe@exam.com
ENV NAME howe
#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
howe


#
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
MAINTAINER howe@exam.com
ENV NAME howe
ENTRYPOINT echo $NAME

[root@docker-node1 docker]# docker run -it --rm --name test example:v4
howe
[root@docker-node1 docker]# docker run -it --rm --name test example:v4 sh
howe


#
[root@docker-node1 docker]# cat Dockerfile 
FROM busybox:latest
MAINTAINER howe@exam.com
ENV NAME howe
EXPOSE 80 443
VOLUME /var/www/html
WORKDIR /var/www/html
RUN touch file

[root@docker-node1 docker]# docker run -it --rm --name test example:v5 
/var/www/html # 

3.4.2 Dockerfile实例

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

[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]# vim Dockerfile 
[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生成镜像 

#通过dockerfile生成镜像
[root@docker-node1 docker]# docker build -t webserver:v1 .
-------------------------------------------------------------
#解决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]# 
[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 .


四 docker 镜像仓库的管理

4.1 docker仓库

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

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

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

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

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

4.2 docker hub

4.2.1 docker hub的使用方法

#登陆官方仓库
[root@docker-node1 ~]# docker login

#登陆信息保存位置
[root@docker-node1 ~]# vim .docker/config.json 

4.3 搭建docker的私有仓库

为什么搭建私有仓库?

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

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

4.3.1 搭建简单的Registry仓库

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.2 为Registry提加密传输

#生成认证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
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 ~]# 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.3.3为仓库建立登陆认证

#安装建立认证文件的工具包
[root@docker-node1 ~]# dnf install httpd-tools -y

#建立认证文件
[root@docker-node1 ~]# mkdir auth
[root@docker-node1 ~]# htpasswd -Bc auth/htpasswd howe
New password: redhat	#密码
Re-type new password: 
Adding password for user howe

#添加认证到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 howe:redhat
{"repositories":["busybox"]}

#登陆测试
[root@docker-node1 ~]# docker login reg.exam.com
Username: howe
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

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


4.4 部署harbor

#安装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 howe

#创建加密密钥
[root@k8s ~]# 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@k8s ~]# mkdir /etc/docker/certs.d/reg.exam.com/ -p
[root@k8s ~]# cp /root/certs/exam.com.crt /etc/docker/certs.d/reg.exam.com/ca.crt
[root@k8s ~]# 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

#下载web服务
[root@k8s harbor]# dnf install httpd -y

#为了方便可以更改web端口
[root@docker-node1 harbor]# vim /etc/httpd/conf/httpd.conf
...
47 Listen 8888
...
[root@docker-node1 harbor]# systemctl restart httpd

#登录docker
[root@k8s harbor]# docker login reg.exam.com
Username: admin
Password: 

网页打开 reg.exam.com/8888

接下来上传镜像看看

#确保登录admin
[root@docker-node1 harbor]# docker login reg.exam.com
Authenticating with existing credentials...
Stored credentials invalid or expired
Username (howe): 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/superhowe/busybox:latest 
[root@docker-node1 ~]# docker push reg.exam.com/superhowe/busybox:latest 
The push refers to repository 

#上传镜像
[reg.exam.com/superhowe/busybox]
d51af96cf93e: Pushed 
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527


五 Docker 网络

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

5.1 docker原生bridge网路

#更改内核参数
[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 

5.2 docker原生网络host

host网络模式需要在容器创建时指定 --network=host

host模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性

[root@docker-node1 ~]# docker run -d --name web -p 80:80 nginx:1.23
a1b8d4fa9c9bfd870c4997d295efb10ff155e50a4a1942d9c99fabe32a02de55

[root@docker-node1 ~]# ifconfig 

5.3 docker 原生网络none

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

[root@docker-node1 ~]# 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-node1 ~]# docker network create my_net1

[root@docker-node1 ~]# docker network ls
2644d485a93e   my_net1                     bridge    local

桥接默认是单调递增

[root@docker-node1 ~]# ifconfig

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

[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 

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

5.4.2 让不同的自定义网络互通

[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)

5.4.3 joined容器网络

[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)
 

5.5. 容器内外网的访问

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网络方式实现跨主机通信

macvlan网络方式

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

macvlan网络间的隔离和连通

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

示例:

#在两台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 数据卷是一个可供容器使用的特殊目录,它绕过了容器的文件系统,直接将数据存储在宿主机上

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

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

6.1 为什么要用数据卷

docker分层文件系统

  • 性能差
  • 生命周期与容器相同

docker数据卷

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

docker提供了两种卷:

  • bind mount
  • docker managed volume

6.2 bind mount 数据卷

  • 是将主机上的目录或文件mount到容器里。
  • 使用直观高效,易于理解。
  • 使用 -v 选项指定路径
  • 格式 :-v选项指定的路径,如果不存在,挂载时会自动创建
[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

6.3 docker managed 数据卷

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

[root@docker-node1 volumes]# ls -l /var/lib/docker/volumes/
drwx-----x 3 root root     19 Aug 30 11:49 39e99109425ea3322d99b73c5672e6414eca041bbafcdee3c8476d74874f788e

[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-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

6.4 数据卷容器

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

#建立数据卷容器
[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

#2.使用数据卷容器
[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
/ # 

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

#备份数据卷
[root@docker-node1 ~]# docker run --volumes-from datavol \
> -v `pwd`:/backup busybox \
> tar zcf /backup/data1.tar.gz /data1

#数据恢复
[root@docker-node1 ~]# docker run --volumes-from datavol \
> -v `pwd`:/backup busybox \
> tar zcf /backup/data1.tar.gz /data1
tar: removing leading '/' from member names
[root@docker-node1 ~]# docker run -it --name test -v vol1:/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
50x.html    file1       index.html

七 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"

[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


#1 命名空间隔离的安全
[root@docker-node1 ~]# docker run -d --name web nginx
b40927e1e0d62f7f7dcd2870a11ef7983d8436d6ba0ecb2ff0d92e533e9f6d3c
[root@docker-node1 ~]# docker inspect web | grep Pid
            "Pid": 4669,
            "PidMode": "",
            "PidsLimit": null,
[root@docker-node1 ~]# cd /proc/4669/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 /sys/fs/cgroup/memory/docker/b40927e1e0d62f7f7dcd2870a11ef7983d8436d6ba0ecb2ff0d92e533e9f6d3c/
/sys/fs/cgroup/memory/docker/b40927e1e0d62f7f7dcd2870a11ef7983d8436d6ba0ecb2ff0d92e533e9f6d3c/
[root@docker-node1 ns]# 

2 控制组资源控制的安全
[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

7.1 Docker的资源限制

Linux Cgroups 的全称是 Linux Control Group。

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

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

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

7.1.1.限制cpu使用

[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的资源限制

2.限制cpu的优先级
#关闭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

7.1.2 限制内存使用

#安装依赖性
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 ~]# 

也可以自建控制器

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

[root@docker-node1 ~]# rm -rf /dev/shm/bigfile 
[root@docker-node1 ~]# echo 209715200 > /sys/fs/cgroup/memory/x1/memory.memsw.limit_in_bytes 

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

7.1.3 限制docker的磁盘io

[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

7.2 Docker的安全加固

7.2.1 容器特权

[root@docker-node1 ~]# docker run --rm -it --privileged busybox
/ # id root
uid=0(root) gid=0(root) groups=0(root),10(wheel)
/ # ip a a 172.25.250.111/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
70: eth0@if71: <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 172.25.250.111/24 scope global eth0
       valid_lft forever preferred_lft forever
/ # fdisk -l
Disk /dev/nvme0n1: 20 GB, 21474836480 bytes, 41943040 sectors
82241 cylinders, 255 heads, 2 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/nvme0n1p1 *  4,4,1       1023,254,2        2048    2099199    2097152 1024M 83 Linux
/dev/nvme0n1p2    1023,254,2  1023,254,2     2099200   41943039   39843840 18.9G 8e Linux LVM
Disk /dev/dm-0: 15 GB, 16101933056 bytes, 31449088 sectors
1957 cylinders, 255 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Disk /dev/dm-0 doesn't contain a valid partition table
Disk /dev/dm-1: 4096 MB, 4294967296 bytes, 8388608 sectors
522 cylinders, 255 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Disk /dev/dm-1 doesn't contain a valid partition table

7.2.2 容器特权的白名单

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

#限制容器对网络有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@if73: <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

8.1 Docker Compose 概述

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

主要功能

1.定义服务:

  • 使用 YAML 格式的配置文件来定义一组相关的容器服务。每个服务可以指定镜像、端口映射、环境变量、存储卷等参数。
  • 例如,可以在配置文件中定义一个 Web 服务和一个数据库服务,以及它们之间的连接关系。

2. 一键启动和停止:

  • 通过一个简单的命令,可以启动或停止整个应用程序所包含的所有容器。这大大简化了多容器应用的部署和管理过程。
  • 例如,使用 docker-compose up 命令可以启动配置文件中定义的所有服务,使用 dockercompose 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)容器是服务的具体实例,每个服务可以有一个或多个容器。容器是基于服务定义的镜像创建的运行实例

8.2 Docker Compose 的常用命令参数

[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

1. docker-compose up 

  • 启动配置文件中定义的所有服务。
  • 可以使用 -d 参数在后台启动服务。
  • 可以使用-f 来指定yml文件
  • 例如: docker-compose up -d

2. docker-compose down

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

#docker-compose down
停止并删除配置文件中定义的所有服务以及相关的网络和存储卷
[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

3. docker-compose start

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

docker-compose start
启动已经存在的服务,但不会创建新的服务
[root@docker-node1 docker]# docker compose start 
[+] Running 2/2
 ✔ Container docker-web-1  Started                                                             0.4s 
 ✔ Container docker-db-1   Started                                                             0.3s

4. docker-compose stop

停止正在运行的服务

docker-compose stop
停止正在运行的服务
[root@docker-node1 docker]# docker compose stop
[+] Stopping 2/2
 ✔ Container docker-web-1  Stopped                                                             0.2s 
 ✔ Container docker-db-1   Stopped                                                            10.1s

5. docker-compose restart

重启服务

二、服务状态查看

1. docker-compose ps

#服务状态查看
[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

2. docker-compose logs

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

[root@docker-node1 docker]# docker compose logs db

三、构建和重新构建服务

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

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

8.3 Docker Compose 的yml文件

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

一、服务(services)
        1. 服务名称(service1_name/service2_name 等):
                每个服务在配置文件中都有一个唯一的名称,用于在命令行和其他部分引用该服务

services:
 web:
   # 服务1的配置
 mysql:
   # 服务2的配置

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

services:
 web:
   images:nginx
 mysql:
   images:mysql:5.7

3. 端口映射(ports):
        将容器内部的端口映射到主机的端口,以便外部可以访问容器内的服务。例如, - "8080:80" 表示将主机的 8080 端口映射到容器内部的 80 端口。

services:
 web:
   image: superhowe/mario
   container_name: game #指定容器名称
    restart: always   #docekr容器自动启动
   expose:
   - 1234 #指定容器暴露那些端口,些端口仅对链接的服务
可见,不会映射到主机的端口
   ports:
      - "80:8080"

4. 环境变量(environment)

        为容器设置环境变量,可以在容器内部的应用程序中使用。例如, VAR1: value1 设置环境变 量 VAR1 的值为 value1

services:
  web:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: redhat

5. 存储卷(volumes):
        将主机上的目录或文件挂载到容器中,以实现数据持久化或共享。

        例如, - /host/data:/container/data 将主机上的 /host/data 目录挂载到容器内的 /container/data 路径

services:
  web:
    image: busybox
    command: ["/bin/sh","-c","sleep 100000"]
    container_name: busybox1
    volumes: 
      - /etc/passwd:/tmp/passwd:ro        #只读挂在本地文件到指定位置

6. 网络(networks):

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

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

7. 命令(command):

覆盖容器启动时默认执行的命令。例如, command: python app.py 指定容器启动时运行 python app.py 命令

services:
 web:
   image: busybox
   container_name: busybox
   #network_mode: mynet2
   command: ["/bin/sh","-c","sleep10000000"]

二、网络(networks)

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

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

三、存储卷(volumes)

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

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 #不打印错误

8.4 企业示例

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

[root@docker-node2 ~]# yum install haproxy -y --downloadonly --downloaddir=/mnt
[root@docker-node2 test]# cd /mnt/
[root@docker-node2 mnt]# ls
haproxy-2.4.22-3.el9_3.x86_64.rpm  hgfs
[root@docker-node2 mnt]# rpm2cpio haproxy-2.4.22-3.el9_3.x86_64.rpm | cpio -id
13488 blocks
[root@docker-node2 mnt]# 
[root@docker-node2 mnt]# ls
etc  haproxy-2.4.22-3.el9_3.x86_64.rpm  hgfs  usr  var
[root@docker-node2 mnt]# 
[root@docker-node2 mnt]# cd etc/
[root@docker-node2 etc]# ls
haproxy  logrotate.d  sysconfig
[root@docker-node2 mnt]# 
[root@docker-node2 etc]# cd haproxy/
[root@docker-node2 haproxy]# ls
conf.d  haproxy.cfg

[root@docker-node2 haproxy]# mkdir /var//lib/docker/volumes/conf
[root@docker-node2 haproxy]# cp haproxy.cfg /var/lib/docker/volumes/conf/
[root@docker-node2 haproxy]# cd /var/lib/docker/volumes/conf/
[root@docker-node2 conf]# ls
haproxy.cfg
[root@docker-node2 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-node2 ~]# cd test/
[root@docker-node2 test]# ls
docker-compose.yml
[root@docker-node2 test]# vim docker-compose.yml 
[root@docker-node2 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-node2 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-node2 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-node2 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-node2 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-node2 test]# curl 172.25.250.200
webserver2
[root@docker-node2 test]# curl 172.25.250.200
webserver1
[root@docker-node2 test]# curl 172.25.250.200
webserver2
[root@docker-node2 test]# curl 172.25.250.200
webserver1

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

  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值