一 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 = 1sysctl --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负载均衡架构实施