使用linux脚本实现模拟docker容器环境运行springboot项目
涉及相关知识
- Namespace 虚拟网络环境 https://blog.csdn.net/liuyij3430448/article/details/127810420
- cgroup https://blog.csdn.net/liuyij3430448/article/details/128222592
- UnionFS https://blog.csdn.net/liuyij3430448/article/details/128255640
- rootfs https://blog.csdn.net/liuyij3430448/article/details/128283244
下面正式开始实验
step1 准备基础的java环境rootfs
使用 jdk-8u231-linux-x64.tar.gz
流程步骤
- 1 在安装docker环境的机器上准备一个空的文件夹
- 2 解压jdk-8u231-linux-x64.tar.gz
- 3 准备Dockerfile文件
- 4 docker build -t centosjdk8 .
- 5 导出容器的运行时 rootfs
Dockefile的内容如下 这里使用centos作为源镜像,目的是为后面的宿主机ubuntu做区分
FROM centos:latest
ENV JAVA_INIT_PATH="/data/jdk"
ENV MY_JAVA_VERSION="1.8"
WORKDIR $JAVA_INIT_PATH
ADD jdk1.8.0_231 jdk1.8.0_231
ENV JAVA_HOME=$JAVA_INIT_PATH/jdk1.8.0_231
ENV JRE_HOME=$JAVA_HOME/jre
ENV PATH=$PATH:$JAVA_HOME/bin
ENV CLASSPATH=:$CLASSPATH:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
创建基于centos的jdk8镜像
docker build -t centosjdk8 . 创建镜像
启动容器并进入验证 java环境已经ok
打开另外一个终端 导出centosjdk8的运行 rootfs
此时已经有了一个最基础的java运行时环境rootfs,这个文件将在后面的联合文件中作为lower层使用模拟docker的基础镜像
step2 准备一个java springboot项目
准备 springboot项目
关键有4个Mapping
- 1 测试访问外网
- 2 测试读取环境变量
- 3 测试限制cpu使用率
- 4 测试端口映射简单的访问
1 测试访问外网
利用HttpURLConnection 访问公网网址
这里为了后面测试模拟docker 容器可以访问公网
2 测试读取环境变量
这里是为了后面测试模拟 docker容器运行环境和主机环境有隔离
3 测试限制cpu使用率
注意 flag是一个boolean private volatile boolean flag = false;
这里是为了后面测试模拟 docker容器 cgroup 资源限制
4 测试端口映射简单的访问
在准备一个简单的 mapping 来测试javaweb项目可以访问,并为后面测试模拟 docker容器 和主机端口映射做准备
mapping测试
以下是4个mapping在我本机 运行后的效果
简单的mapping 输出
访问公网网址
获取本机环境变量
测试限制cpu使用率
将springboot项目打包好待用
这将模拟我们平时自己的springboot项目
step3 在实验的宿主机上模拟联合文件目录与内容
测试用ubuntu系统为 18.04.6 LTS
验证一下 当前的ubuntu系统是没有安装java环境的
准备联合文件系统需要使用的 各种文件夹
**使用 docker inspect 可以看到docker 容器也是使用类似的联合文件系统 **
将刚才创建好的centosjdk8.tar 解压到lower文件夹
cd lower
tar -xf centosjdk8.tar
并将springboot项目放到upper 下的service文件夹中
以上步骤类似使用Dockerfile创建自己的项目镜像
类似这样的Dockerfile
FROM centosjdk8
VOLUME ["/service"]
WORKDIR "/service"
COPY my-docker-demo-sp-goods.jar my-docker-demo-sp-goods.jar
step4 准备一个自己的cgroup 来做资源控制
docker 安装完成后会在 系统默认的/sys/fs/cgroup 下挂载自己的层级 (下图为我的一个docker环境)
本次实验 我们只测试限制cpu使用率
step5 准备一个基础的网络环境
docker 安装完成后 会创建一个docker0的网桥(交换机)用于docker内部访问
可以使用brctl 工具来安装网桥
centos安装 yum install bridge-utils
ubuntu安装 apt install bridge-utils
使用以下命令来创建网桥和配置ip
brctl addbr mydocker0
ip link set mydocker0 up
ip addr add local 172.17.0.1/16 dev mydocker0
这样容器外部的网络环境就完成
step6 配置自己的Name space 模拟docker 容器运行环境
创建命名空间隔离切换rootfs 模拟 docker 容器环境
相关命令如下
unshare --mount --net --pid --uts --ipc --fork /bin/bash #需要有独立的命名空间
mount --make-rslave /
mkdir -p /mydockeroverlay/merged #创建用于挂载的文件夹
mount -t overlay myoverlay -o lowerdir=/mydockeroverlay/lower,upperdir=/mydockeroverlay/upper,workdir=/mydockeroverlay/work/ /mydockeroverlay/merged 挂载联合文件系统
cd /mydockeroverlay/merged
mkdir old-root
pivot_root /mydockeroverlay/merged /mydockeroverlay/merged/old-root #切换roofs
cd /
mount -t proc rp /proc
umount -l old-root
exec /bin/sh
PATH=$PATH:/data/jdk/jdk1.8.0_231/bin #配置环境变量
程序已经启动
step7 Name space 内的网络配置
1 将net命名空间与外部文件绑定 让ip netns 命令可以操作命名空间
2 配置命名空间网络
创建虚拟网卡,并将网卡一段加入到命名空间 一端加入到mydocker0网桥,并配置ip
相关命令
ip link add eth0 type veth peer name veth0 #创建虚拟网卡
ip link set eth0 netns mydockernetns #添加虚拟网卡
brctl addif mydocker0 veth0
ip link set veth0 up
ip netns exec mydockernetns ip link
ip netns exec mydockernetns ip addr add local 172.17.0.29/16 dev eth0 #配置虚拟网卡ip
ip netns exec mydockernetns ip link set eth0 up
ip netns exec mydockernetns ip link set lo up
ip netns exec mydockernetns ifconfig
ip netns exec mydockernetns route
3 测试访问springboot项目
可以访问到项目了
step8 配置防火墙 让Name space 实现和主机端口映射 和 访问公网
目前通过主机ip 访问 容器内部服务还无法连通
现在需要在主机上配置ip防火墙 达到 docker run -p 5599:5599 的效果
给命名空间内部配置默认网关
ip netns exec mydockernetns route add default gw 172.17.0.1
配置ip防火墙
首先确认系统内核 ip forwarding 是开启的
cat /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv4/ip_forward
配置ip防火墙
让命名空间内部可以访问外网
iptables -t nat -A POSTROUTING -s 172.17.0.1/16 -o enp0s3 -j MASQUERADE
让命名空间端口与主机端口映射
iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 5599 -j DNAT --to 172.17.0.29:5599
现在通过主机ip 访问 springboot项目成功
step9 测试Cgroup 网络隔离
访问http://192.168.0.54:5599/cpu?s=30 可以发现 cpu使用率很高没有被管理
原因是 还没有把进程加入到cgroup中管理
**先停掉springboot项目 再把命名空间内部的 /bin/sh 的pid写入到tasks中 **
再次启动springboot项目 并访问http://192.168.0.54:5599/cpu?s=30 可以看到cpu使用率得到控制
参考文章
https://blog.csdn.net/liuyij3430448/article/details/128255640
https://blog.csdn.net/liuyij3430448/article/details/127810420
https://blog.csdn.net/liuyij3430448/article/details/128222592
https://blog.csdn.net/liuyij3430448/article/details/128283244