文章目录
一、Docker和虚拟机的区别
为什么Docker比较比VM快?
(1) docker有着比虚拟机更少的抽象层。由亍docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
虚拟机与docker架构对比图
(2) docker利用的是宿主机的内核,而不需要Guest OS。因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。仍而避免引寻、加载操作系统内核返个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,返个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返个过程,因此新建一个docker容器只需要几秒钟。
-
Docker与虚拟机对比
总结虚拟机是正儿八经的存在一层硬件虚拟层,模拟出了运行一个操作系统需要的各种硬件,例如CPU,MEM,IO等设备。然后在虚拟的硬件上安装了一个新的操作系统Guest OS。所以在Windows宿主机上面可以跑Linux虚拟机。因为多了一层虚拟,所以虚拟机的性能必然会有所损耗。Docker容器是由Docker Deamon(Docker Deamon是运行在宿主机上面的一个后台进程,负责拉起和设置容器)拉起的一个个进程,通过Docker Deamon设置完Namespace和Cgroup之后,本质上就是一个运行在宿主机上面的进程。因为没有一层虚拟的Guest OS,所以Docker轻量级很多。但是有利就有弊,由于Docker 容器直接运行在宿主机上面,安全性就相对较差些,另外也没有办法在Windows上面运行Linux的容器,如果容器里面的应用对特定系统内核有要求也不能运行在不满足要求的宿主机上面。
Docker 容器总结起来就是利用Linux Namespace做资源隔离,Cgroup做资源上限限制,rootfs做文件系统 运行在宿主机上面的一个特殊进程。
二、Docker三要素
●镜像:一个面向Docker容器引擎的只读模板
●容器:从镜像创建的运行实例
●仓库:集中保存镜像的地方;分公有和私有仓库
三、Docker基础命令
1、本地文件拷贝到容器内:
docker cp index.jsp 容器id:/usr/local/tomcat/webapps/ROOT
2、镜像操作
●查看docker版本:docker version
●搜索nginx镜像(公有仓库):docker search nginx
●下载nginx镜像:docker pull nginx;下载后存放在/var/lib/docker
●查看镜像列表
docker images #查看下载镜像信息列表
docker inspect nginx:latest #获取镜像详细信息
●为镜像添加新标签
docker tag nginx:latest nginx:web
●两种方式删除镜像
注意:删除某一个镜像时,只要有容器在使用某一个镜像,必须先删除容器,才能删除镜像。
(1)删除镜像+标签名
(2)删除镜像id
注意:只有当镜像id对应标签仅剩一个时,才能使用镜像id的方式进行删除;否则出现如下报错
或者也可以在最后加上-f选项,一次性删除
●存出镜像并命名为nginx,存到/opt目录下
docker save -o /opt/nginx.tar nginx:latest
●载入镜像
docker load < /opt/nginx
3、容器操作
●创建容器
docker create -it nginx:latest /bin/bash
-i:让容器的标准输入保持打开
-t:让Docker分配一个伪终端
●查看容器运行状态
docker ps -a -a:列出所有的容器,包括未运行的容器
Created:已创建; Up:运行中
●启动执行命令查看系统根目录
一般启动容器流程:
(1)docker pull centos --下载镜像
(2)docker create -it centos:latest /bin/bash
(3)docker start d4a99affa677
通过run命令启动:(先去查找现有的镜像中有没有,没有先下载,再启动)
docker run centos:latest /usr/bin/bash -c ls /
执行完成会关闭,状态是Exited(容器可以做一次性的处理,处理完就释放资源,做到了最小成本控制)
容器持续在后台执行(通过执行死循环)
docker run -d centos:latest /bin/bash -c "while true;do echo hello;done"
使用 docker logs 容器id 命令,可以查看容器内的标准输出
●终止容器运行
docker stop 0401f589d5ed(CONTAINER ID)
●进入容器(该容器一定要在Up状态)
docker exec -it 0f0ba9207b21 /bin/bash
●导出容器
docker export cc4a8b1d428c > /opt/nginx_bak
●导入容器(会生成镜像,而不会创建容器)
cat /opt/nginx_bak | docker import - nginx:bak
●删除容器(容器必须为停止状态)
docker stop e885c37fb2eb
docker rm e885c37fb2eb
●批量删除容器
docker ps -a | awk '{print "docker rm "$1}' | bash
docker ps -a | sed -n '2,$p' | awk '{print "docker rm "$1}' | bash
四、Docker镜像的构建
1、Docker镜像的分层
自下而上制作镜像
1.from 后面跟基础镜像
2.add脚本
3.挂载共享空间 数据卷
4.CMD命令执行脚本
2、基于已有镜像容器创建
1、docker create -it 原镜像名 /bin/bash
2、docker commit -m "new" -a "chen" 已有容器id 新镜像名:标签
-m:说明信息
-a:作者信息
-p:生成过程中停止容器的运行
docker images | grep 标签
3、基于本地模板创建
1.导入本地镜像debian-7.0-x86-minimal.tar.gz
2.cat debian-7.0-x86-minimal.tar.gz | docker import - 镜像名:标签
3.docker images | grep 标签
4、基于Dockerfile创建
●Dockerfile是由一组指令组成的文件
●Dockerfile结构四部分
基础镜像信息
维护者信息
镜像操作指令
容器启动时执行指令
●Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以“#”号开头的注释
●Dockerfile操作指令
指令 | 含义 |
---|---|
FROM 镜像 | 指定新镜像所基于的镜像,第一条指令必须为FROM指令,每创建一个镜像就需要一条FROM指令。 |
MAINTAINER 名字 | 说明新镜像的维护人信息 |
RUN命令 | 在所基于的镜像上执行命令,并提交到新的镜像中 |
CMD [“要运行的程序”,“参数1”,“参数2”] | 指令启动容器时要运行的命令或者脚本,Dockerfile只能有一条CMD命令,如果指定多条则只能最后一条被执行 |
EXPOSE 端口号 | 指定新镜像加载到Docker时要开启的端口(EXPOSE暴露的是容器内部端口,需要再映射到一个外部端口上) |
ENV 环境变量 变量值 | 设置一个环境变量的值,会被后面的RUN使用 |
ADD 源文件/目录 目标文件/目录 | 将源文件复制到目标文件(最好的用途是将本地tar文件解压到镜像中) |
COPY 源文件/目录 目标文件/目录 | 将本地主机上的文件/目录复制到目标地点,源文件/目录要与Dockerfile在相同的目录中 |
VOLUME [“目录”] | 在容器中创建一个挂载点(VOLUME是宿主机中的某一个目录挂载到容器中) |
USER 用户名/UID | 指定运行容器时的用户 |
WORKDIR 路径 | 为后续的RUN、CMD、ENTRYPOINT指定工作目录(WORKDIR类似于cd,但是只切换目录一次,后续的RUN命令就可以写相对路径了) |
ONBUILD 命令 | 指定所生成的镜像作为一个基础镜像时所要运行的命令 |
HEALTHCHECK | 健康检查 |
CMD指令可以指定容器启动时默认执行的命令,但它可以被docker run命令的参数覆盖掉。
ENTRYPOINT 指令和CMD类似,它也是用户指定容器启动时要执行的命令,但如果dockerfile中也有CMD指令,CMD中的参数会被附加到ENTRYPOINT指令的后面。 如果这时docker run命令带了参数,这个参数会覆盖掉CMD指令的参数,并也会附加到ENTRYPOINT 指令的后面。
这样当容器启动后,会执行ENTRYPOINT 指令的参数部分。
可以看出,相对来说ENTRYPOINT指令优先级更高。
对于目录而言,COPY 和 ADD 命令具有相同的特点:只复制目录中的内容而不包含目录自身
CMD和ENTRYPOINT的区别
CMD指令可以指定容器启动时默认执行的命令,但它可以被docker run命令的参数覆盖掉。
ENTRYPOINT 指令和CMD类似,它也是用户指定容器启动时要执行的命令,但如果dockerfile中也有CMD指令,CMD中的参数会被附加到ENTRYPOINT指令的后面。 如果这时docker run命令带了参数,这个参数会覆盖掉CMD指令的参数,并也会附加到ENTRYPOINT 指令的后面。
这样当容器启动后,会执行ENTRYPOINT 指令的参数部分。
可以看出,相对来说ENTRYPOINT指令优先级更高。
优先级:ENTRYPOINT>CMD>docker run
Dockerfile文件生成apache镜像实例:
1.vim Dockerfile (Dockerfile名字不可更改)
\#新镜像基于的基础镜像(基础镜像未下载会先下载)
FROM centos:7
\#维护镜像的用户信息
MAINTAINER This is chen
\#镜像操作指令安装apache软件
RUN yum -y update
RUN yum -y install httpd
\#开启80端口
EXPOSE 80
\#复制网址首页文件
ADD index.html /var/www/html/index.html
\#将执行脚本复制到镜像中
ADD run.sh /run.sh
RUN chmod 755 /run.sh
\#启动容器时执行脚本
CMD ["/run.sh"]
此处注意一个细节:每加载一步会生成一个临时的容器,加载完后会删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-brdWkCf3-1614049334483)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/055003e9f82c4711b0046865ff96cb8c/clipboard.png)]
2.vim run.sh #和Dockerfile文件位于相同目录下
#!/bin/bash
rm -rf /run/httpd/* #删除进程文件
exec /usr/sbin/apachectl -D FOREGROUND #启动apache
3.vim index.html #编辑首页文件
this is web
4.生成镜像docker build -t httpd:test . (注意别忘了末尾有".")
5.新镜像运行容器
docker run -d -p 1216:80 httpd:test
-p:映射到宿主机指定端口
-P:映射到宿主机随机端口
6.测试容器是否成功运行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AXEDCtJo-1614049334484)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/94357e8784af45999cfef2b90f1b763d/clipboard.png)]
五、Docker的四种网络模式
1、实现原理
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。
2、网络详解
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
f9ad4320a5f2 bridge bridge local
894917639bf3 host host local
39da54945dad none null local
#安装docker时,它会自动创建三个网络,bridge(创建容器默认连接到该网络)、none和host
1)、host模式
容器将不会获得一个独立的Network Namespace(网络命令空间),而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fGzgtANL-1614049334485)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/4fd47499f2a94e09b3bfbd9aad84e235/clipboard.png)]
2)、Container模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信
3)、none模式
使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。该模式关闭了容器的网络功能
4)、bridge模式
此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及iptables nat表配置与宿主机通信
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QwrfHcOS-1614049334485)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/07f0c302363a4f2e9bbd5b4468e0ecfa/clipboard.png)]
3、自定义网络如何配置
#创建容器时默认使用的是桥接模式,但是使用bridge不支持为容器指定IP
[root@localhost ~]# docker run -itd --name test1 --network bridge --ip 172.17.0.10 centos:7 /bin/bash
20dc45293929f81013a60391bef2626f581a8d3d4f29b8a87ac8b1f9b585ab2a
docker: Error response from daemon: user specified IP address is supported on user defined networks only. #提示想要为容器指定IP只能在用户自定义的网络中才行
#配置自定义固定IP
[root@localhost ~]# docker network create --subnet=172.31.0.0/24 test
#创建自定义网络test
[root@localhost ~]# docker run -itd --name web1 --net test --ip 172.31.0.10 centos:7 /bin/bash
#创建一个容器,指定网络为test,指定IP地址172.31.0.10
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bf8sdyPq-1614049334486)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/8600e70f42c64ccca0ab409472bb0ee4/clipboard.png)]
六、Docker数据管理
1、为什么要进行数据管理操作
●方便查看容器内产生的数据
●多容器间实现数据共享
例如:需要给多个容器中的网站站点上传网页内容时,可以高效的部署网页。
2、两种管理方式
●数据卷
数据卷是容器和宿主之间的数据共享
●数据卷容器
数据卷容器是容器和容器之间的数据共享
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rh2pKKju-1614049334486)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/47a64e939777442c9c47cc76c0169255/clipboard.png)]
3、数据卷操作实例
1.将宿主机目录中的/var/www挂载到容器中的/data1中(如果目录不存在都会自动创建)
docker run -v /var/www:/data1 --name web1 -it centos:7 /bin/bash
2.在容器中/data1目录下创建文件进行测试
[root@bb58030283e7 /]# cd /data1/
[root@bb58030283e7 data1]# touch 123.txt
3.回到宿主机/var/www查看
[root@node1 ~]# cd /var/www/
[root@node1 www]# ls
123.txt
4、数据卷容器操作实例
1.创建数据卷容器web10
docker run --name web10 -v /data1 -v /data2 -it centos:7 /bin/bash
2.新容器web100挂载数据卷容器web10
docker run -it --volumes-from web10 --name web100 centos:7 /bin/bash
(web100容器会自动关联web10容器中的数据卷)
3.在新容器web100的/data1中创建文件进行测试
[root@2ad42960c2aa data1]# cd /data1/
[root@2ad42960c2aa data1]# ls
[root@2ad42960c2aa data1]# touch 1.txt
4.回到数据卷容器web10的/data1中查看
[root@b10f5d5ae9d5 /]# cd data1/
[root@b10f5d5ae9d5 data1]# ls
1.txt
5、私有仓库建立步骤
1、下载registry镜像
2、客户端设置daemon.json文件,指定私有仓库位置;
"insecure-registries": ["14.0.0.10:5000"],
3、生成registry容器,开放5000端口
docker run -d -p 5000:5000 -v /registry:/data/registry registry
4、给要上传的镜像打上标签
5、上传镜像
6、获取私有仓库列表查看是否上传成功
7、测试私有仓库下载镜像
#–privileged 让容器内的root拥有真正的root权限。否则,container内的root只是外部的一个普通用户权限。
[root@localhost systemctl]# docker run --privileged -it -v /sys/fs/cgroup:/sys/fs/cgroup:ro
七、Docker Compose容器编排
1、Docker Compose简介
●一个定义及运行多个Docker容器的工具
●Docker Compose非常适合组合使用多个容器进行开发的场景
3.2Docker Compose文件格式及编写注意事项
●YAML是一种标记语言很直观的数据序列化格式
●文件格式及编写注意事项
不支持制表符tab键缩进,需要使用空格缩进
通常开头缩进2个空格
字符后缩进1个空格,如冒号、逗号、横杆
用#号注释
如果包含特殊字符用单引号引起来
布尔值必须用引号括起来
2、Compose命令说明
●基本的使用格式
docker-compose [options] [COMMAND] [ARGS]
●docker-compose选项
--verbose 输出更多调试信息
--version 打印版本并退出
-f,--file FILE 使用特定的compose模板文件,默认为docker-compose.yml
-p,--project-name NAME 指定项目名称,默认使用目录名称
3、compose部署
#以docker-ce为基础
上传docker-compose命令包到/usr/local/bin目录下
chmod +x /usr/local/bin/docker-compose
#在/root目录下创建compose_tomcat目录
[root@localhost ~]# mkdir compose_tomcat/
目录结构如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aDlrHswi-1614049334487)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/d513953ded104c95aaff0decac7e7feb/clipboard.png)]
docker-compose.yml配置文件详解:
https://www.jianshu.com/p/2217cfed29d7
一份标准配置文件应该包含 version、services、networks 三大部分,其中最关键的就是 services 和 networks 两个部分
[root@localhost compose_tomcat]# vim docker-compose.yml
version: '3'
services:
tomcat:
hostname: tomcat
build: #基于一份 Dockerfile创建容器
context: ./tomcat
dockerfile: Dockerfile
ports:
- 8080:8080
networks:
- tomcat
volumes:
- ./wwwroot:/usr/local/tomcat/webapps/ROOT #注意tomcat站点位置
nginx:
hostname: nginx
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- 1216:80
- 1226:443
networks:
- nginx
volumes:
- ./nginxroot:/usr/local/nginx/html
networks:
tomcat:
nginx:
[root@localhost compose_tomcat]# docker-compose -f docker-compose.yml up -d
八、Harbor私有仓库
Harbor私有仓库部署与管理
Harbor的每个组件都是以Docker容器的形式构建的,使用docker-compose来对它进行部署
Docker harbor有可视化的web管理界面,可以方便管理Docker镜像,又提供了多个项目的镜像权限管理及控制功能
使用 Docker 命令在本地通过 127.0.0.1 来登录和推送镜像
默认情况下,Register 服务器在端口 80 上侦听。
//登录
docker login -u admin -p Harbor12345 http://127.0.0.1
//下载镜像进行测试 下载镜像进行测试
docker pull nginx
//镜像打标签 (网页上也会有提示、模板)
docker tag nginx 127.0.0.1/myimages/nginx:v1
//上传镜像到 上传镜像到 Harbor
docker push 127.0.0.1/myimages/nginx:v1
使用Harbor仓库时遇到的故障:
以上操作都是在 Harbor 服务器本地操作。如果其他客户端上传镜像到 Harbor,就会报
如下错误。
出现这问题的原因 Docker Registry 交互默认使用的是 HTTPS,但是搭建私有镜像默认使用的是 HTTP 服务,所以与私有镜像交互时出现以下错误。
[root@localhost ~]# docker login -u admin -p Harbor12345 http://14.0.0.20
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Error response from daemon: Get https://14.0.0.20/v2/: dial tcp 14.0.0.20:443: connect: connection refused
如何解决:
[root@client ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --insecure-registry 14.0.0.20 -- containerd=/run/containerd/containerd.sock
[root@client ~]# systemctl daemon-reload
[root@client ~]# systemctl restart docker
要更改 Harbor 的配置文件时,请先停止现有的 Harbor 实例并更新 Harbor.cfg;然后运行 prepare 脚本来填充配置;最后重新创建并启动 Harbor 的实例。
1.停止现有的 Harbor 实例
docker-compose down -v
[root@localhost harbor]# pwd
/usr/local/harbor
[root@localhost harbor]# ls
common docker-compose.yml harbor.v1.2.2.tar.gz NOTICE
docker-compose.clair.yml harbor_1_1_0_template install.sh prepare
docker-compose.notary.yml harbor.cfg LICENSE upgrade
2.更新 Harbor.cfg
[root@localhost harbor]# vim Harbor.cfg
3.运行 prepare 脚本来填充配置
[root@localhost harbor]# ./prepare
4.重新创建并启动 Harbor 的实例
如果出现如下报错: docker-compose up -d
九、Docker consul容器服务更新与发现
Docker Consul容器服务更新与发现原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G6Wac0Vo-1614049334488)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/e87db744e15a4a2596a9019c7386df9d/clipboard.png)]
工作流程:
当后面容器增加时,registrator注册容器中的服务—》通知consul server更新—》consul template模板进行更新,自动修改nginx.conf中的upstream参数
Registrator监控新建的Docker容器,并且检查判定这些容器提供的服务。从我们的目的出发,任何监听在某个端口的程序都是服务。Registrator在容器内发现的任务服务,都将被添加到一个服务注册端,比如Consul或etcd
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CqSbuteV-1614049334488)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/fed68f21bcf047b3804e5aa3faae7a0f/clipboard.png)]
准备template nginx模板文件,参数以变量形式写入
在consul服务器节点上操作
[root@localhost consul]# vim /root/consul/nginx.ctmpl
upstream http-server {
{{range service "nginx"}}
server {{.Address}}:{{.Port}};
{{end}}
}
consul-template是一个守护进程,用于实时查询consul集群信息,并更新文件系统上任意数量的指定模板,生成配置文件。更新完成后,可以选择运行shell命令执行更新操作,重新加载nginx。这种强大的抽象功能和查询语言模板可以使consul-template特别适合动态的创建配置文件。例如:创建nginx反向代理。
十、资源分配
1、为什么要做资源分配?
容器和虚拟机的区别:
虚拟机不需要做,因为虚拟机在创建的时候已经做了资源分配(配额),(虚拟CPU,虚拟内存,虚拟磁盘等)
而容器共享内核资源,所以需要做Cgroup,可以按照往年监控的数据,查看cpu等资源的耗用情况来进行分配
2、Cgroup资源配置方法
Docker是通过Cgroup来控制容器使用的资源配额,包括CPU、内存、磁盘i/o三大方面,基本覆盖了常见的资源配额和使用量控制。
Cgroup是Control Groups的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如CPU、内存、磁盘IO等)的机制,被docker等很多项目用于实现进程资源控制。Cgroup本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O或内存的分配控制等具体的资源管理功能。这些具体的资源管理功能称为Cgroup子系统,有以下几大子系统实现:
blkio:设置限制每个块设备的输入输出控制。例如:磁盘,usb等
CPU:使用调度程序为cgroup任务提供CPU的访问。
cpuacct:产生cgroup任务的CPU资源报告。
cpuset:如果是多核心的cpu,这个子系统会为cgroup任务分配单独的CPU和内存。
devices:允许或拒绝cgroup任务对设备的访问。
freezer:暂停和恢复cgroup任务。
memory:设置每个cgroup的内存限制以及产生内存资源报告。
net_cls:标记每个网络包以供cgroup方便使用。
ns:命名空间子系统。
perf_event:增加了对每个group的监测跟踪的能力,可以监测属于某个特定的group的所有线程以及运行在特定CPU上的线程。
3、使用stress工具测试CPU和内存
#使用Dockerfile来创建一个基于Centos的stress工具镜像
[root@localhost ~]# mkdir stress
[root@localhost ~]# vim stress/Dockerfile
[root@localhost ~]# cd stress/
[root@localhost stress]# vim Dockerfile
FROM centos:7
MAINTAINER chen
RUN yum -y install wget
RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum -y install stress
[root@localhost stress]# docker build -t centos:stress .
#使用如下命令创建容器,命令中的–cpu-shares参数值不能保证可以获得1个vcpu或者多少GHz的CPU资源,它仅是一个弹性的加权值。
[root@localhost ~]# docker run -itd --cpu-shares 100 centos:stress
说明:默认情况下,每个Docker容器的CPU份额都是1024。单独一个容器的份额是没有意义的。只有在同时运行容器时,容器的cpu加权的效果才能显现。
例如:两个容器A、B的cpu份额分别为1000和500,在cpu进行实际片分配的时候,容器A比容器B多一倍的机会获得cpu的时间片。但分配的结果取决于当时主机和其他容器的运行状态,实际上也无法保证容器A一定能获得cpu时间片。比如容器A的进程一直是空闲的,那么容器B是可以获取比容器A更多的cpu时间片的。极端情况下,例如主机上只运行了一个容器,即使它的cpu份额只有50,它也可以独占整个主机的cpu。
例如:cpu时间片:1秒
容器A:50% 0.5秒
容器B:25% 0.25秒
容器C:25% 0.25秒
平均值层面:CPU给A容器充0.5秒,给B容器充0.25秒
#可以通过cpu share可以设置容器使用cpu的优先级,比如启动了两个容器及运行查看cpu使用百分比。
[root@localhost stress]# docker run -itd --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10
#stress -c 10:容器产生10个子函数进程
[root@localhost stress]# docker exec -it dd0e42e372ff /bin/bash
[root@dd0e42e372ff /]# top
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kRXYNUTB-1614049334489)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/d698aaa35b874ef8b86d2aefae36f2db/clipboard.png)]
[root@localhost ~]# docker run -itd --name cpu512 --cpu-shares 512 centos:stress stress -c 10
[root@localhost ~]# docker exec -it ddfccf1cac40 /bin/bash
[root@ddfccf1cac40 /]# top
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-006tOZkG-1614049334490)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/b8ed9a1ab4d441e38927c15b9219bbf2/clipboard.png)]
#可以发现两个容器cpu使用率是2:1
4、CPU周期限制
Docker提供了–cpu-period、–cpu-quota两个参数控制容器可以分配到的CPU时钟周期。
–cpu-period是用来指定容器对CPU的使用要在多长时间内做一次重新分配。
–cpu-quota是用来指定在这个周期内,最多可以有多少时间来跑这个容器。
与–cpu-shares不同的是,这种配置是指定一个绝对值,容器对CPU资源的使用绝对不会超过配置的值。
cpu-period和cpu-quota的单位为微秒(μs)。cpu-period的最小值为1000微秒,最大值为1秒,默认值为0.1秒(100000μs)
cpu-quota的值默认为-1,表示不做控制。cpu-period和cpu-quota参数一般联合使用。
例如:容器进程需要每1秒使用单个cpu的0.2秒时间,可以将cpu-period设置为1000000即1秒,cpu-quota设置为200000(0.2秒)。
在多核情况下,如果允许容器进程完全占用两个cpu,则可以将cpu-period设置为100000即0.1秒,cpu-quota设置为200000即0.2秒
[root@localhost ~]# docker run -itd --cpu-period 100000 --cpu-quota 200000 centos:stress
[root@localhost ~]# docker exec -it 16b6689aabc6 /bin/bash
[root@16b6689aabc6 /]# cd /sys/fs/cgroup/
[root@16b6689aabc6 cgroup]# ls
blkio cpuacct freezer net_cls perf_event
cpu cpuset hugetlb net_cls,net_prio pids
cpu,cpuacct devices memory net_prio systemd
[root@16b6689aabc6 cgroup]# cd cpu
[root@16b6689aabc6 cpu]# ls
cgroup.clone_children cpu.rt_period_us cpuacct.usage
cgroup.event_control cpu.rt_runtime_us cpuacct.usage_percpu
cgroup.procs cpu.shares notify_on_release
cpu.cfs_period_us cpu.stat tasks
cpu.cfs_quota_us cpuacct.stat
[root@16b6689aabc6 cpu]# cat cpu.cfs_period_us
100000
[root@16b6689aabc6 cpu]# cat cpu.cfs_quota_us
200000
5、CPU Core控制
对多核CPU的服务器,Docker还可以控制容器运行使用哪些CPU内核,即使用–cpuset-cpus参数。这对具有多CPU的服务器尤其有用,可以对需要高性能计算的容器进行性能最优的配置。
[root@localhost ~]# docker run -itd --name cpu1 --cpuset-cpus 1-2 centos:stress
#执行以上命令表示创建的容器只能用1、2两个cpu。最终生成的cgroup的cpu内核配置如下:
[root@localhost ~]# docker exec -it 75be98d74dcc /bin/bash
top - 07:34:23 up 45 min, 0 users, load average: 0.00, 0.01, 0.04
[root@75be98d74dcc /]# cat /sys/fs/cgroup/cpuset/cpuset.cpus #cpuset:cpu集合
1-2
[root@75be98d74dcc /]# stress -c 5 & #让容器产生5个子函数进程,并在后台运行
[root@75be98d74dcc /]# top #使用top命令查看cpu工作情况(top进去后按1,显示每个cpu的工作情况)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oR447WFt-1614049334490)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/00522c0fbd0244268fb09886cc94401e/clipboard.png)]
#通过下面指令可以看到容器中进程与cpu内核的绑定关系
[root@localhost ~]# docker exec 75be98d74dcc taskset -c -p 1 #-p 1 表示容器中第一个进程pid为1被绑定到cpu1和2上
pid 1's current affinity list: 1,2
6、CPU配额控制参数的混合使用
通过cpuset-cpus参数指定容器A使用cpu内核0,容器B只是用CPU内核1.
在主机上只有这两个容器使用对应cpu内核的情况,它们各自占用全部的内核资源,cpu-shares没有明显效果。
cpuset-cpus、cpuset-mems参数只在多核、多内存节点上的服务器上有效,并且必须与实际的物理配置匹配,否则也无法达到资源控制的目的。
在系统具有多个cpu内核的情况下,需要通过cpuset-cpus参数为容器设置cpu内核才能方便的进行测试。
#创建容器cpu3,仅使用cpu0核心,加权值为512
[root@localhost ~]# docker run -itd --name cpu3 --cpuset-cpus 0 --cpu-shares 512 centos:stress stress -c 1
[root@localhost ~]# docker exec -it 4eb80db7a397 bash
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YRcGdMTd-1614049334491)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/a750924664f44e499dcfa424cf00374a/clipboard.png)]
#创建容器cpu4,仅使用cpu0核心,加权值为1024
[root@localhost ~]# docker run -itd --name cpu4 --cpuset-cpus 0 --cpu-shares 1024 centos:stress stress -c 1
[root@localhost ~]# docker exec -it 327038e98aa4 bash
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QsPvNjgq-1614049334491)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/04fa2f4a5b684628bcc0ac61a1858b49/clipboard.png)]
7、内存限额
与操作系统类似,容器可使用的内存包括两部分:物理内存和Swap
Docker通过下面两组参数来控制容器内存的使用量。
-m或–memory:设置内存的使用限额,例如100M、1024M
–memory-swap:设置内存+swap的使用限额
执行如下命令允许该容器最多使用200M的内存和300M的swap
[root@localhost ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
–vm 1:启动1个内存工作线程
–vm-bytes 280M:每个线程分配280M内存
默认情况下,容器可以使用主机上的所有空闲内存。
与cpu的cgroups配置类似,Docker会自动为容器在目录/sys/fs/cgroup/memory/docker/<容器的完整长id>中创建相应cgroup配置文件
注意:如果让工作线程分配的内存超过300M,分配的内存超过限额,stress线程报错,容器退出。
[root@localhost ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M
8、bps和iops的限制
bps是byte per second,每秒读写的数据量。
iops是io per second,每秒io的次数。
可通过以下参数控制容器的bps和iops:
–device-read-bps,限制读某个设备的bps。
–device-write-bps,限制写某个设备的bps。
–device-read-iops,限制读某个设备的iops。
–device-write-iops,限制写某个设备的iops。
示例:限制容器写/dev/sda的速率为5MB/s。
[root@localhost ~]# docker run -it --device-write-bps /dev/sda:5MB centos:stress
[root@7675c030fd53 /]# dd if=/dev/zero of=test bs=1M count=1024 oflag=direct
^C22+0 records in
22+0 records out
23068672 bytes (23 MB) copied, 4.40131 s, 5.2 MB/s
#通过dd命令测试在容器中写磁盘的速度是否为5MB/s。因为容器的文件系统是在主机/dev/sda上的,在容器中写文件相当于对主机/dev/sda进行写操作。另外,oflag=direct指定用direct IO方式写文件,这样 --device-write-bps才能生效。
结果表明限速5MB/s左右。作为对比测试,如果不限速,结果如下:
[root@server ~]# docker run -it centos:stress
[root@07b87cdda205 /]# dd if=/dev/zero of=test bs=1M count=1024 oflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 1.01479 s, 1.1 GB/s
十一、Docker-TLS加密通讯
1、使用TLS加密通讯原因
为了防止链路劫持、会话劫持等问题导致Docker通信时被中间人攻击,c/s两端应该通过加密方式通讯。
2、基础知识
1.对称密钥,例如DES、3DES、AES,长度不同,长度越长安全越高,解密速度越慢。
2.非对称密钥,分为公钥和私钥,例如RSA 公钥:所有人可知(锁),私钥(钥匙)个人身份信息,不可抵赖。
3.封装在证书中:个人信息,密钥,有效期
4.ca:证书颁发机构 ca证书
密钥key–》身份签名(csr)–》服务器/客户端(结合)制作证书pem
证书pem发送给客户端,客户端通过证书验证才能访问容器
3、TLS加密通讯部署过程:
1.修改服务器主机名为server,并添加到本地解析文件
[root@localhost ~]# hostnamectl set-hostname server
[root@localhost ~]# su
[root@server ~]# vim /etc/hosts
127.0.0.1 server
2.创建ca密钥(ca-key.pem)
[root@server ~]# openssl genrsa -aes256 -out ca-key.pem 4096 #256为密钥长度;4096为字节数
Generating RSA private key, 4096 bit long modulus
.......++
...............++
e is 65537 (0x10001)
Enter pass phrase for ca-key.pem: #输入密码123123(自定义)
Verifying - Enter pass phrase for ca-key.pem: #确认密码123123
3.创建ca根证书文件(ca.pem)
[root@server ~]# openssl req -new -x509 -days 1000 -key ca-key.pem -sha256 -subj "/CN=*" -out ca.pem #req:签名;x509:国际标准;sha256:指定哈希256位加密算法;subj:项目名称
Enter pass phrase for ca-key.pem: #输入123123
--------------------------------------------------------------------------------------------------------------------------------
4.创建服务器私钥
[root@server ~]# openssl genrsa -out server-key.pem 4096 #genrsa:非对称密钥
Generating RSA private key, 4096 bit long modulus
.....................................................................................++
..............................................................++
e is 65537 (0x10001)
[root@server ~]# ls
anaconda-ks.cfg ca.pem server-key.pem 公共 视频 文档 音乐
ca-key.pem initial-setup-ks.cfg stress 模板 图片 下载 桌面
5.签名私钥
[root@server ~]# openssl req -subj "/CN=*" -sha256 -new -key server-key.pem -out server.csr
6.使用ca证书与私钥证书签名
[root@server ~]# openssl x509 -req -days 1000 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem
Signature ok
subject=/CN=*
Getting CA Private Key
Enter pass phrase for ca-key.pem: #输入123123
[root@server ~]# ls
anaconda-ks.cfg ca.srl server.csr 公共 图片 音乐
ca-key.pem initial-setup-ks.cfg server-key.pem 模板 文档 桌面
ca.pem server-cert.pem stress 视频 下载
----------------------------------------------------------------------------------------------------------------------------
7.生成客户端密钥
[root@server ~]# openssl genrsa -out key.pem 4096
Generating RSA private key, 4096 bit long modulus
....................................++
.......................................................................++
e is 65537 (0x10001)
8.签名客户端
[root@server ~]# openssl req -subj "/CN=client" -new -key key.pem -out client.csr
9.创建配置文件
[root@server ~]# echo extendedKeyUsage=clientAuth > extfile.cnf
10.签名证书,输入123123,需要(签名客户端,ca证书,ca密钥)
[root@server ~]# openssl x509 -req -days 1000 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for ca-key.pem:
\---------------------------------------------------------------------------------------------------------------------------------
11.删除多余文件
[root@server ~]# rm -rf ca.srl client.csr extfile.cnf server.csr
12.修改docker服务文件文件
[root@server ~]# vim /lib/systemd/system/docker.service
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g9CvMbIM-1614049334492)(C:/%E6%9C%89%E9%81%93/%E7%AC%94%E8%AE%B0/weixinobU7Vjr77MsBJ6yQf29GVWik52DI/5427f18f061b4fc78428b5dd67262373/clipboard.png)]
[root@server ~]# mkdir /tls
[root@server ~]# mv ca.pem /tls
[root@server ~]# mv server-cert.pem /tls
[root@server ~]# mv server-key.pem /tls/
[root@server ~]# mv cert.pem /tls/
[root@server ~]# mv key.pem /tls/
[root@server ~]# ls /tls/
ca.pem cert.pem key.pem server-cert.pem server-key.pem
13.重载进程,重启docker服务
[root@server ~]# systemctl daemon-reload
[root@server ~]# systemctl restart docker
14.将/tls目录下的ca.pem、cert.pem、key.pem三个文件复制给客户端
[root@server tls]# scp ca.pem root@14.0.0.30:/etc/docker/
[root@server tls]# scp cert.pem root@14.0.0.30:/etc/docker/
[root@server tls]# scp key.pem root@14.0.0.30:/etc/docker/
-----------------------------------------------------------------------------------------------------------------------------------
15.到客户端14.0.0.30进行测试
[root@localhost docker]# vim /etc/hosts
加入:14.0.0.20 server
[root@localhost ~]# cd /etc/docker/ #注意要切换到服务端传证书文件的目录下
[root@localhost docker]# docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H tcp://server:2376 ps -a #测试成功,成功访问服务端容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
327038e98aa4 centos:stress "stress -c 1" About an hour ago Exited (137) About an hour ago cpu4
4eb80db7a397 centos:stress "stress -c 1" About an hour ago Exited (137) About an hour ago cpu3