Docker_v2

Docker / 2023-01-10

Docker_v2

一、Docker资源配额

(一)、概述

  • Docker通过cgroup来控制容器使用的资源限制,可以对docker限制的资源包括CPU、内存、磁盘,来实现一个安全策略,防止业务容器被黑而影响到服务器

(二)、具体操作

## 指定docker容器可以使用的cpu份额
docker run -it --cpu-shares 512 centos  /bin/bash
	· --cpu-shares:cpu配额
	· 注意:设置的 cpu share 并不是 CPU 资源的绝对数量,而是一个相对的权重值。某个容器最终能分配到的 CPU 资源取决于它的 cpu share 占所有容器 cpu share 总和的比例。通过 cpu share 可以设置容器使用 CPU 的优先级。

## CPU core核心控制
docker run -itd --name docker1 --cpuset-cpus 0,1 centos /bin/bash 
	· --cpuset-cpus 0,1		# 绑定cpu到第一个和第二个核上
	· --cpuset-mems	0,1,3	# 使用节点0、1、3上的内存,但只对具有NUMA拓扑(具有多CPU、多内存节点)的服务器上作用比较大

## stress压测工具,需要用到epol源安装
# 参数解释
-?        显示帮助信息
-v        显示版本号
-q        不显示运行信息
-n        显示已完成的指令情况
-t        --timeout  N  指定运行N秒后停止        
          --backoff   N   等待N微妙后开始运行
-c        产生n个进程 :每个进程都反复不停的计算随机数的平方根,测试cpu
-i        产生n个进程 :每个进程反复调用sync(),sync()用于将内存上的内容写到硬盘上,测试磁盘io
-m        --vm n 产生n个进程,每个进程不断调用内存分配malloc()和内存释放free()函数 ,测试内存
          --vm-bytes B  指定malloc时内存的字节数 (默认256MB)
          --vm-hang N   指定在free栈的秒数   
-d        --hadd n  产生n个执行write和unlink函数的进程
          -hadd-bytes B  指定写的字节数
          --hadd-noclean  不unlink        
	注:时间单位可以为秒s,分m,小时h,天d,年y,文件大小单位可以为K,M,G
# 例:产生2个cpu进程,2个io进程,20秒后停止运行
stress -c 2 -i 2 --verbose --timeout 20s

## docker容器控制内存
docker run -it  -m 128m centos
	· -m(--memory)		# 允许容器使用的内存上限为128M

## docker容器控制IO
 docker run -it  -v /var/www/html/:/var/www/html --device /dev/sda:/dev/sda --device-write-bps /dev/sda:2mb centos  /bin/bash
	· --device	参数					 # 将主机设备添加到容器
	· --device-read-bps 设备名:速率		# 限制容器磁盘 IO
 
## docker容器运行结束自动释放资源 
docker run -it --rm --name test centos  sleep 6
	· --rm		# 运行完毕后自动删除容器
	· sleep		# sleep命令可以用来将目前动作延迟一段时间

Docker限制容器使用CPU的方法

二、Dockerfile

(一)、介绍

  • Dockerfile是用来构建 docker 镜像的构建文件,定义了一切的步骤,源代码。

  • 构建步骤

    • 编写一个dockerfile文件
    • docker build 构建成为一个镜像
    • docker run 运行镜像
    • docker push 发布镜像(DockerHub 、阿里云仓库)

image-20200612234419262

(二)、DockerFile的编写

1、构建指令

docker build -t . image:tag
	· -t:构建镜像
	· . :当前目录下的dockerfile文件
	· -f:指定具体的dockerfile文件

2、DockerFile指令

# 基础镜像
 FROM
	· 例:FROM nginx

# 作者信息,没必要写
 MAINTAINER
 	· 例:MAINTAINER zzz

# 指定在当前镜像构建过程中要运行的命令,可以一个RUN接多个命令,中间用 ; 隔开
 RUN
    · RUN <command> (shell模式)
        · 例:RUN echo hello
    · RUN [“executable”,“param1”,“param2”](exec模式)
        · 等价于/bin/bash -c echo hello
        · 例:RUN [“/bin/bash”,”-c”,”echo hello”]

# ADD 指令和 COPY 的使用格式一致。在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>,根据是否需要自动解压来决定。如果单纯复制文件,推荐使用COPY
 ADD
	· ADD [--chown=<user>:<group>] <源路径1>...  <目标路径>
		· 例:ADD --chown=nginx:nginx /data/test.tar.gz  /test
	· ADD [--chown=<user>:<group>] ["<源路径1>",...  "<目标路径>"]
		· 例:ADD --chown=nginx:nginx ["/data/test.tar.gz","/test"]
    · [--chown=<user>:<group>]:可选参数,改变复制到容器内文件的拥有者和属组。
    · <目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
    · <源路径>:源文件或者源目录,这里可以是通配符表达式。
    	· 例:ADD hom* /test
    	· 例:ADD hom?.tar.gz /test

# 把dockerfile当前目录下的文件拷贝到容器中(不解压tar包)
 COPY
	· COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
		· 例:COPY --chown=nginx:nginx /data1  /data2
	· COPY [--chown=<user>:<group>] ["<源路径1>",...  "<目标路径>"]
		· 例: COPY --chown=nginx:nginx ["/data1","/data2"]
    · [--chown=<user>:<group>]:可选参数,改变复制到容器内文件的拥有者和属组。
    · <目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
    · <源路径>:源文件或者源目录,这里可以是通配符表达式。
    	· 例:COPY hom* /test
    	· 例:COPY hom?.txt /test

# 指定容器的默认工作目录(填写绝对路径)
 WORKDIR
	· WORKDIR <工作目录路径>
		· 例:WORKDIR /etc/nginx

# 定义匿名数据卷,在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
 VOLUME
	· VOLUME /sys/fs/cgroup可以提高权限
	· VOLUME ["<路径1>", "<路径2>"...]
		· 例:VOLUME ["/data1","/data2"]
	· VOLUME <路径>
		· 例:VOLUME /data

# 声明端口,方便使用者配置映射。在运行时使用随机端口映射 -P 时,会自动映射到 EXPOSE 的端口。可以是一个或者多个端口,也可以指定多个EXPOSE。
 EXPOSE          
	· EXPOSE <端口1> [<端口2>...]
		· 例:EXPOSE 80 8080 8888

# 容器启动的时候执行的初始命令,会被docker run 命令行中指定的命令替换
 CMD
	· CMD[“executable”,“param1”,“param2”](exec模式)
		· 例:CMD ["/usr/sbin/nginx","-g","daemon off;"]
	· CMD command (shell模式)
		· 例:CMD /usr/sbin/nginx -g daemon off;
	· CMD [“param1”,”param2”](作为ENTRYPOINT指令的默认参数)

# 容器启动的时候执行的初始命令,不能被替换,如果同时使用CMD和ENTRYPOINT,CMD命令将作为ENTRYPOINT命令的参数。如果存在多个 ENTRYPOINT 指令,仅最后一个生效。但如果运行 docker run 时使用了 --entrypoint 选项,y覆盖 entrypoint指令指定的程序
ENTRYPOINT
	· ENTERYPOINT [“executable”,“param1”,“param2”](exec模式)
		· 例:ENTERYPOINT["nginx", "-c","/etc/nginx/nginx.conf"]
	· ENTERYPOINT command (shell模式)
		· 例:ENTERYPOINT nginx -c /etc/nginx/nginx.conf

# 类似于触发器,当构建一个被继承DockerFile 这个时候就会运行ONBUILD的指令。触发指令
ONBUILD
	· ONBUILD <其它指令>
		· 例:ONBUILD rm -rf /*   😏

# 构建的时候设置环境变量,跟 -e 一样
ENV	
	· ENV <key> <value>
		· 例:ENV a b
	· ENV <key>=<value>...
		· 例:ENV a=b

# LABEL 可以为生成的镜像添加元数据标签信息(metadata),以键值对的形式,尽可能地把多个labels合并到一个LABEL指令
LABEL
	· LABEL <key>=<value> <key>=<value> <key>=<value> ...

# 与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
ARG
	· ARG <参数名>[=<默认值>]
		· 例:ARG a=b
	· 在构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖

# 用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
USER
    · USER <用户名>[:<用户组>]
    	· 例:
            · USER user       
            · USER uid
            · USER user:group 
            · USER uid:gid
            · USER user:gid    
            · USER uid:group
    
# 用于指定某个程序或者指令来监控 docker 容器服务的运行状态,通过该指令指定一行命令,用这行命令来判断容器主进程的服务状态。Docker 默认只能通过容器进程的返回码判断容器的状态,HEALTHCHECK则能够从业务角度判断应用是否有异常,当一个容器设置了HEALTHCHECK之后,除了正常的up状态,它多了一个healthy状态,这个状态初始为starting。当健康检查通过后,它变成了healthy(不管之前是什么状态)。当连续出现几次失败后,就变成unhealthy。
HEALTHCHECK
    · HEALTHCHECK NONE	# 如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
        · HEALTHCHECK [选项] CMD <命令>
            · --interval=<间隔> :两次健康检查的间隔,默认为 30 秒;
            · --timeout=<时长> :健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
            · --retries=<次数> :当连续失败指定次数后,则将容器状态视为 unhealthy ,默认 3 次
        · 例:HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/ || exit 1 	# 如果返回 1 则退出(curl -f 连接失败时不显示http错误,-s静默模式)

3、例:

## 基于alpine镜像构建nginx
FROM alpine
COPY init.sh /
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
    apk update  && \
    apk add curl bash vim libxml2-dev openssl-dev libjpeg-turbo-dev binutils && \
    apk add libpng-dev libxpm-dev freetype-dev gd-dev gettext-dev libmcrypt-dev && \
    addgroup nginx  && \
    adduser -G nginx -D -s /sbin/nologin nginx  && \
    apk add nginx && \
    chmod +x /init.sh && \
    mkdir -p /code/kod && \
    chmod -R 777 /code && \
    chown -R nginx.nginx /code
ADD ./kodbox.1.26.tar /code/kod
ADD ./default.conf /etc/nginx/http.d
EXPOSE  80
ENTRYPOINT ["/init.sh"]

(三)、编写注意事项及优化方案

  • 注意事项

    • 构建docker时必须在该目录中命名一个dockerfile文件
    • 同一个目录中不能有两个dockerfile文件
  • 优化方案

    • 尽可能选择简单的基础镜像,例如alpine、scratch、busybox
    • 尽可能减少dockerfile构建过程中的层级
    • 针对dockerfile内容进行修改的操作尽可能放在后面,让它走缓存,而不是重新再次生成缓存
    • 借助于.dockerignore文件将不需要推送的文件排除掉,因为在镜像构建过程中会将dockerfile文件所在的目录中的所有文件进行推送,但是这个隐藏文件不存在,需要自行创建,在其中添加不需要推送的文件名即可

三、容器互联

(一)、docker 0

  • docker0是docker管理容器网络的虚拟逻辑网卡,起到桥接网络的功能,每启动一个容器,docker都会给容器分配一个ip。

  • 桥接模式使用的是 veth-pair 技术,veth-pair是成对的虚拟设备接口,一端连着协议,一端彼此相连。

    正因为有这个特性,veth-pair可以充当一个桥梁,用来连接各种虚拟网络设备。

[root@docker ~]# ip a
  ......
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:7b:c9:f3:6b brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:7bff:fec9:f36b/64 scope link 
       valid_lft forever preferred_lft forever
       
## 网桥管理工具,需要yum安装
yum -y install bridge-utils
brctl show 		# 可以查看到有一个docker0的网桥设备
  • ----link是用于将某容器的名字和IP关系解析到运行的容器中,从而保证容器之间直接通过名称进行通信,注意,是单向通信,局限性较大。
  • 具体的操作就是将指向的容器名的IP添加到了/etc/hosts解析文件中,当作一个域名来解析。
例: 基于centos镜像创建test1和test2容器,并让test2能ping通test1
docker run -d -P --name test1 centos
docker run -d -P --name test2 --link test1 centos

(三)、自定义网络

1、网络模式

  • bridge:桥接模式,也是docker 0默认的网络模式
  • none:不配置网络
  • host:共用宿主机网络,容器使用宿主机的网卡,传输速率高,但是容易出现端口冲突和IP地址冲突
  • container:两个容器共享同一网络,ip,mac地址完全相同,传输高效,彼此不依赖

2、自定义网络命令

## 创建自定义网络
docker network create -d bridge --subnet 172.18.0.0/24 --gateway 172.18.0.1 zzz
	· -d  bridge    			# 定义网络模式,-d是 --driver 的缩写
	· --subnet 172.18.0.0/24	# 定义网段
	· --gateway 172.18.0.1		# 定义网段网关
	· zzz					   # 自定义网络名称

## 查看网络模式
docker network ls

## 删除自定义网络
docekr network rm xxx

## 查看自定义网络元数据信息
docker network inspect xxx

## 创建容器时指定网络模式
docker run --name xxx -d -P --net xxx XXX 
	· --net		# 指定网络模式,在容器启动时默认指定网络为 --net bridge,也就是docker 0

(四)、跨主机通信

1、macvlan

  • 通过docker 0 构建一个桥接网卡,实现容器通过桥接网络到宿主机网络上,但是容易导致网段ip不足
## 所有节点创建一个相同的macvlan网络,来实现本机容器桥接到宿主机网络
docker network create -d macvlan --subnet 10.0.0.0/24 --gateway 10.0.0.254 -o parent=eth0 macvlan_1
	· -d  macvlan    			# 定义网络模式,-d是 --driver 的缩写
	· --subnet 10.0.0.0/24		# 定义子网 范围
	· --gateway 10.0.0.254		# 定义子网网关
	· -o  parent=xxx			# 指定宿主机可以上网的网卡

## 运行容器并指定macvlan网络即可
docker run -d --network macvlan_1 --ip 10.0.0.110 --name mac_1 alpine:latest tail -f /etc/hosts
	· --ip 指定容器的固定ip地址

2、overlay

  • 通过隧道统一注册地址信息到数据库中,从而通过隧道实现网络通信
## 安装consul容器,consul存储ip地址的分配
docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap

## 在需要通讯的docker主机配置consul接口
vim /etc/docker/daemon.json
{
  "registry-mirrors": ["https://gk0lnxyj.mirror.aliyuncs.com"],	
  "cluster-store": ["consul://10.0.0.201:8500"],		 # 指定consul配置存储节点
  "cluster-advertise": ["10.0.0.199:2376"]				# 每台机器各自需要被发现的接口地址
}
## 重启docker
systemctl restart docker

## 创建overlay网络,配置的网段要与docker主机的网端不冲突,只需在一个节点创建即可
docker network create -d overlay --subnet 172.16.2.0/24 --gateway 172.16.2.254  overlay_1

## 最后创建容器使用即可
docker run -d --network overlay_1 --name over_1 alpine:latest tail -f /etc/hosts

overlay 网络交互原理