架构第二周作业-20230709

一、实现并总结容器跨主机的通信过程

【实验环境】

root@ubuntu20-server1-111:~# docker --version
Docker version 24.0.4, build 3713ee1
root@ubuntu20-server1-111:~# ip a show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:16:32:4b brd ff:ff:ff:ff:ff:ff
    inet 192.168.119.111/24 brd 192.168.119.255 scope global eth0

root@ubuntu20-server2-112:~# docker --version
Docker version 24.0.4, build 3713ee1
root@ubuntu20-server2-112:~# ip a show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:fa:e8:c4 brd ff:ff:ff:ff:ff:ff
    inet 192.168.119.112/24 brd 192.168.119.255 scope global eth0

【实验过程】

# 修改两台主机的默认dockerIP地址段,默认都是172.17.0.1
## 修改第一台主机默认 docker 地址段为 10.10.0.1/24
root@ubuntu20-server1-111:~# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.10.0.1/24
root@ubuntu20-server1-111:~# systemctl daemon-reload
root@ubuntu20-server1-111:~# systemctl restart docker
## 修改第二台的为 10.20.0.1/24
root@ubuntu20-server2-112:~# vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.20.0.1/24
root@ubuntu20-server2-112:~# systemctl daemon-reload
root@ubuntu20-server2-112:~# systemctl restart docker

# 在宿主机添加静态路由,使其访问对应的容器可以让本机转发到对应的容器的宿主机
## 第一台主机
root@ubuntu20-server1-111:~# route add -net 10.20.0.0/24 gw 192.168.119.112
root@ubuntu20-server1-111:~# iptables -A FORWARD -s 192.168.119.0/24 -j ACCEPT
## 第二台主机
root@ubuntu20-server2-112:~# route add -net 10.10.0.0/24 gw 192.168.119.111
root@ubuntu20-server2-112:~# iptables -A FORWARD -s 192.168.119.0/24 -j ACCEPT

# 进入到容器查看IP地址
## 第一台主机
[root@27b67febb447 /]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:0a:0a:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.10.0.2/24 brd 10.10.0.255 scope global eth0
       valid_lft forever preferred_lft forever
## 第二台主机
[root@37928c559315 /]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:0a:14:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.20.0.2/24 brd 10.20.0.255 scope global eth0
       valid_lft forever preferred_lft forever
       
# 测试连通性
[root@27b67febb447 /]# ping -c 1 10.20.0.2
PING 10.20.0.2 (10.20.0.2) 56(84) bytes of data.
64 bytes from 10.20.0.2: icmp_seq=1 ttl=62 time=0.336 ms

--- 10.20.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.336/0.336/0.336/0.000 ms

[root@37928c559315 /]# ping -c1 10.10.0.2
PING 10.10.0.2 (10.10.0.2) 56(84) bytes of data.
64 bytes from 10.10.0.2: icmp_seq=1 ttl=62 time=0.469 ms

--- 10.10.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.469/0.469/0.469/0.000 ms

【跨主机通信原理】

root@ubuntu20-server1-111:~# tcpdump -nn -vvv -i veth86b6808 -vvv -nn ! port 22 and ! arp and ! port 53 -w veth86b6808.pacp
root@ubuntu20-server1-111:~# tcpdump -nn -vvv -i eth0 -vvv -nn ! port 22 and ! arp and ! port 53 -w eth0_server11.pacp

root@ubuntu20-server2-112:~# tcpdump -nn -vvv -i eth0 -vvv -nn ! port 22 and ! arp and ! port 53 -w eth0_server12.pacp
root@ubuntu20-server2-112:~# tcpdump -nn -vvv -i veth15e7d49 -vvv -nn ! port 22 and ! arp and ! port 53 -w veth15e7d49@if4.pacp

1、容器1 10.10.0.2 去 ping 容器2 10.20.0.2,目的地址与本机不在同一个网段,将该数据包发送给自己的网关

2、网关收到该报文后转发给宿主机内核,宿主机收到后发现不是自己的,查看路由表,根据路由表从自己的eth0网卡转发给另一个容器的宿主机

3、容器2的宿主机收到后,发现目的地址是 10.20.0.2,通过宿主机2的 docker0 网卡发送给容器2
image

二、总结Dockerfile的常见指令

DockerFile 是一个可以被 Docker 程序解释的文本文件,它由指定的命令组成,在构建镜像的过程中,Docker 程序会读取 DockerFile 文件内容并生成一个临时容器,然后在临时容器中从上到下顺序执行 DockerFile 的指令,当执行完所有指令后再把临时容器提交为一个Docker镜像,这样就完成了一个镜像的构建。

# 指定当前镜像所引用的父镜像
FROM 

# 设置镜像的属性标签
## 镜像的维护者信息,目前不推荐使用
MAINTAINER
## 推荐使用 LABEL,键值对形式
LABEL author="xxx@gmail.com"
LABEL version="1.0"

# 用于添加宿主机本地的文件、目录、压缩文件等资源到镜像中去,会自动解压tar.gz格式的压缩包,不自动解压zip包
ADD [--chown=<user>:<group>]<src>... <dest>
ADD --chown=root:root test /opt/test

# COPY 也可以复制相关文件到镜像中,用法同ADD,但COPY不可以解压缩任何文件
COPY [--chown=<user>:<group>]<src>... <dest>

# 设置容器的环境变量
ENV NANE="Jerry"

# 指定运行操作的用户
USER <user>[:<group>] or USER <UID>[:<GID>]

# 执行shell命令,但必须以非交互式的方式执行
RUN yum -y install net-tools && cd /etc/

# 定义volume
VOLUME ["/data/data1"]

# 定义当前工作目录,会切换到指定的目录中
WORKDIR /data/test1

# 声明要把容器的某些端口映射到宿主机,非主要
EXPOSE <port> [<port>/<protocol>...]

# 定义容器默认的启动命令或脚本
CMD ["nginx","-g","daemon off"]

# ENTRYPOINT 也可以定义容器在启动时默认执行的命令或脚本,当和CMD命令混用时,会将CMD命令当作参数传递给ENTRYPOINT后面的脚本,可以在脚本对参数做判断并对容器进行初始化操作

# 定义后续的命令以什么身份执行,默认root
USER

三、基于Dockerfile Nginx镜像并验证可以启动为容器

# 准备好相关文件
root@ubuntu20-server1-111:/data/dockerfile/nginx# ls
Dockerfile  index.html  nginx-1.18.0.tar.gz  nginx.conf

# 编辑Dockerfile文件
root@ubuntu20-server1-111:/data/dockerfile/nginx# cat Dockerfile 
FROM ubuntu:22.04
LABEL author="xxx@gmail.com"

RUN apt update && apt -y install  iproute2 ntpdate tcpdump telnet traceroute nfs-kernel-server nfs-common lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev  gcc openssh-server iotop unzip zip make
RUN mkdir -p /apps/nginx && useradd -r -s /sbin/nologin nginx

ADD nginx-1.18.0.tar.gz /usr/local/src/

RUN cd /usr/local/src/nginx-1.18.0 && ./configure --prefix=/apps/nginx/ --user=nginx --group=nginx && make && make install && ln -s /apps/nginx/sbin/nginx /usr/sbin/nginx && chown -R nginx:nginx /apps/nginx/

RUN mkdir -p /apps/nginx/run/
ADD nginx.conf /apps/nginx/conf/
ADD index.html /apps/nginx/html/


CMD ["nginx","-g","daemon off;"]

# 构建镜像
docker build -t 192.168.119.113/myserver/nginx:20230718 .

# 启动镜像
root@ubuntu20-server1-111:/data/dockerfile/nginx# docker run -it -p 8080:80 192.168.119.113/myserver/nginx:20230718

# 验证结果如下

image

四、部署单机harbor并实现镜像的上传与下载

1、安装 harbor

# 安装前准备好docker环境
root@ubuntu20-server3-113:~# docker --version
Docker version 24.0.4, build 3713ee1

# 准备harbor安装包
root@ubuntu20-server3-113:~# ls
harbor-offline-installer-v2.8.2.tgz

# 安装harbor
root@ubuntu20-server3-113:~# tar xvf harbor-offline-installer-v2.8.2.tgz -C /usr/local/src/
root@ubuntu20-server3-113:~# cd /usr/local/src/harbor/
root@ubuntu20-server3-113:/usr/local/src/harbor# cp harbor.yml.tmpl harbor.yml
## 可根据自己需要修改文件,注释掉https,暂时不用
root@ubuntu20-server3-113:/usr/local/src/harbor# vim harbor.yml
hostname: 192.168.119.113
harbor_admin_password: 123456
data_volume: /data/harbor
## 开始安装,--with-trivy 是开启安全扫描
root@ubuntu20-server3-113:/usr/local/src/harbor# ./install.sh --with-trivy
···
···
[Step 5]: starting Harbor ...
[+] Running 11/11
 ✔ Network harbor_harbor        Created                                                           0.0s 
 ✔ Container harbor-log         Started                                                           0.4s 
 ✔ Container registryctl        Started                                                           0.7s 
 ✔ Container registry           Started                                                           1.0s 
 ✔ Container harbor-db          Started                                                           1.0s 
 ✔ Container harbor-portal      Started                                                           1.1s 
 ✔ Container redis              Started                                                           1.1s 
 ✔ Container harbor-core        Started                                                           1.5s 
 ✔ Container trivy-adapter      Started                                                           1.4s 
 ✔ Container harbor-jobservice  Started                                                           1.9s 
 ✔ Container nginx              Started                                                           1.9s 
✔ ----Harbor has been installed and started successfully.----

2、使用浏览器进入harbor页面
image

3、创建一些仓库
image
image

4、镜像的上传

# 将alpine镜像重新打标签
root@ubuntu20-server1-111:~# docker tag alpine:latest 192.168.119.113/myserver/alpine:20230718

# docker默认登录镜像仓库使用https,我们这里使用http,需要修改配置文件,添加不安全的仓库,使其信任
## 添加该行
root@ubuntu20-server1-111:~# vim /etc/docker/daemon.json 
{
  "insecure-registries": ["192.168.119.113"]
}
## 重启
systemctl restart docker.service

# 登录到需要上传镜像的仓库
root@ubuntu20-server1-111:~# docker login 192.168.119.113
Username: admin
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/#credentials-store

Login Succeeded

# 开始上传镜像
root@ubuntu20-server1-111:~# docker push 192.168.119.113/myserver/alpine:20230718 
The push refers to repository [192.168.119.113/myserver/alpine]
8d3ac3489996: Pushed 
20230718: digest: sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3 size: 528

# 结果如下

image

5、镜像下载

# 另一台主机下载该镜像仓库时,也需要配置"insecure-registries"
root@ubuntu20-server2-112:~# vim /etc/docker/daemon.json
{
  "insecure-registries": ["192.168.119.113"]
}
root@ubuntu20-server2-112:~# systemctl restart docker.service

# 开始拉取镜像
root@ubuntu20-server2-112:~# docker pull 192.168.119.113/myserver/alpine:20230718
20230718: Pulling from myserver/alpine
59bf1c3509f3: Pull complete 
Digest: sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3
Status: Downloaded newer image for 192.168.119.113/myserver/alpine:20230718
192.168.119.113/myserver/alpine:20230718

五、基于systemd实现容器的CPU及内存的使用限制

对于Linux主机,如果没有足够的内存来执行其它重要的任务,将会抛出OOM等异常,随后系统会开始杀死进程以释放内存,凡是运行在宿主机的内存都有可能被kill,包括docker和其它应用程序。默认容器是没有资源限制的,会尽可能的去使用系统的资源,如果因为某些原因容器大量的申请资源,使得系统资源不足而杀死掉了某些重要的进程,导致相关服务宕机,因此需要对容器资源进行限制。

【实验环境】

# 注意Cgroup的驱动是systemd
root@ubuntu20-server1-111:~# docker info | grep -i "cgroup driver"
 Cgroup Driver: systemd
root@ubuntu20-server1-111:~# docker -v
Docker version 24.0.4, build 3713ee1

#如果不是,需要修改
root@ubuntu20-server1-111:~# vim /etc/docker/daemon.json 
{
  "exec-opts": ["native.cgroupdriver=systemd"]
}

【实验过程】

1、拉取压力测试镜像
root@ubuntu20-server1-111:~# docker pull lorel/docker-stress-ng
# 查看相关帮助信息
docker run -it --rm lorel/docker-stress-ng --help

2、不限制容器使用的内存时
# 启动两个工作进程,每个工作进程最大128M
# --vm N 启动N个进程对内存进行压测  --vm-bytes 128M 每个进程使用多少内存进行压测
root@ubuntu20-server1-111:~# docker run -it --rm lorel/docker-stress-ng --vm 2 --vm-bytes 128M

2.1、查看结果
root@ubuntu20-server1-111:~# docker stats
CONTAINER ID   NAME            CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O   PIDS
d521e828546c   admiring_wing   285.81%   260.8MiB / 3.798GiB   6.71%     946B / 0B   0B / 0B     5

3、限制容器使用的内存最大为200M
# -m 200M 限制容器使用的最大内存为200M
root@ubuntu20-server1-111:~# docker run -it --rm -m 200M lorel/docker-stress-ng --vm 2 --vm-bytes 128M

3.1、查看结果
root@ubuntu20-server1-111:~# docker stats
CONTAINER ID   NAME            CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O     PIDS
128db81b1dfb   thirsty_raman   156.02%   199.9MiB / 200MiB   99.97%    806B / 0B   5.95GB / 0B   5

4、限制容器最多使用1核CPU,内存210M;压力测试2核CPU,内存256M
# --cpus 1 限制容器使用1核CPU,--cpu N 启动N个进程
root@ubuntu20-server1-111:~# docker run -it --rm -m 210M --cpus 1 lorel/docker-stress-ng --vm 2 --vm-bytes 128M --cpu 2

4.1 查看结果
CONTAINER ID   NAME                   CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O     PIDS
68170178a74e   distracted_northcutt   106.76%   209.9MiB / 210MiB   99.97%    806B / 0B   1.59GB / 0B   7

六、总结镜像的分层构建流程

1、获取官方原始镜像:官方原始镜像是构建其他镜像的基础,通常是一个最小的、基本的Linux发行版,例如Alpine Linux。
2、安装通用程序设置:在基础镜像上,安装通用的一些程序,以构建出一个通用的基础镜像版本。
3、定义应用程序和依赖项:在基础镜像上,定义应用程序基本环境,正确安装和配置应用程序及其依赖项。
4、定义业务镜像:每个业务镜像在自己业务的基础镜像上,运行特定的配置文件和业务代码。
5、测试镜像:镜像构建完成后,需要测试镜像是否满足生产需求。
6、分发镜像:如果镜像符合预期并通过测试,将镜像分发到仓库中供大家使用。

七、总结基于lxcfs对容器的内存及CPU的资源限制

在容器中是从/proc/cpuinfo中获取到CPU的核数,但容器中的/proc文件系统是物理机的,内存也是显示宿主机中的/proc/meminfo信息,因此不够准确。**lxcfs **是通过文件挂载的方式将宿主机中关于系统的相关信息读取出来,通过docker的volume挂载给容器内部的proc系统,然后让docker内的应用读取proc中信息就是限定后的资源,其实还是读取宿主机真实的 proc。

# 安装 lxcfs,实现更加准确的限制
root@ubuntu20-server1-111:~# apt -y install lxcfs

# 注意挂载磁盘选项
root@ubuntu20-server1-111:~# mkfs.xfs /dev/sdb
root@ubuntu20-server1-111:~# vim /etc/fstab
/dev/sdb      /var/lib/docker    xfs       defaults,pquota      0 0
root@ubuntu20-server1-111:~# mount -a
root@ubuntu20-server1-111:~# systemctl restart docker.service

# 限定内存为200M,CPU为1核
root@ubuntu20-server1-111:~# docker run -it -m 200M --cpus 1 \
-v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw \
-v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw \
-v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw \
-v /var/lib/lxcfs/proc/stat:/proc/stat:rw \
-v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \
-v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw \
centos:7.9.2009 /bin/bash

---  未使用 lxcfs 限制前 ---
[root@bb9761103925 /]# free -h
              total        used        free      shared  buff/cache   available
Mem:           3.8G        334M        2.7G        1.5M        819M        3.2G
Swap:          3.8G          0B        3.8G
[root@bb9761103925 /]# top
top - 13:26:08 up 8 min,  0 users,  load average: 0.06, 0.08, 0.06
Tasks:   2 total,   1 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  3982404 total,  2804284 free,   331008 used,   847112 buff/cache
KiB Swap:  3994620 total,  3994620 free,        0 used.  3400468 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                             
      1 root      20   0   11836   3052   2648 S   0.0  0.1   0:00.01 bash                                                                                
     19 root      20   0   56184   3892   3364 R   0.0  0.1   0:00.00 top

---  使用 lxcfs 限制后 ---
[root@3a25abf512b5 /]# free -h
              total        used        free      shared  buff/cache   available
Mem:           200M        2.6M        197M          0B          0B        197M
Swap:          3.8G          0B        3.8G
[root@3a25abf512b5 /]# top
top - 13:26:33 up 2 min,  0 users,  load average: 0.08, 0.04, 0.05
Tasks:   2 total,   1 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   204800 total,   201896 free,     2904 used,        0 buff/cache
KiB Swap:  3994620 total,  3994620 free,        0 used.   201896 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                           
      1 root      20   0   11836   3060   2656 S   0.0  1.5   0:00.01 bash                                                                                              
     22 root      20   0   56192   3856   3312 R   0.0  1.9   0:00.00 top
posted @ 2023-07-20 21:32  wuhaolam  阅读(14)  评论(0编辑  收藏  举报