pod中将代码与运行环境分离
# 0. 前言
我们在创建一个 python 的 web 服务的镜像时,一般的做法是,将 python 环境与代码打包成一个镜像,然后将这个镜像进行发布。
现在有个需求就是将 python 环境和代码分别构造成两个镜像,让他们进行解耦,并且将他们编排在一个 pod 中。
本文介绍如何将 pod 中的代码与运行的环境进行拆分。
# 1. 思路
首先我们将代码打包成镜像 A,再将 python 运行环境打包成镜像 B,通过编排在 Pod 中的 InitContainer 设置为镜像 A,并将其内的代码拷贝到挂载的 emptyDir 存储卷中,然后在镜像 B 中挂载相同的存储卷,在使用运行环境中的 python 去执行存储卷中拷贝过来的代码即可。
# 2. 案例
# 2.1 创建代码镜像
先创建一个简单的 python web 程序 main.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "Hello, World!"
app.run(host="0.0.0.0")
2
3
4
5
6
7
8
9
10
我们再创建包含代码镜像的 Dockerfile,做的事情是将 main.py 文件拷贝到镜像的根目录下,文件命名为Dockerfile_code
FROM busybox:latest
COPY main.py /
2
我们通过 docker build
开始创建镜像,镜像名称为 demo_code,默认 tag为 latest
docker build . -t "demo_code" -f Dockerfile_code
这个时候我们的代码镜像创建好了。
# 2.2 创建 python 运行环境
我们开始创建 python 运行环境镜像的 Dockerfile,以 python3 的镜像为基础,并安装 flask 库,文件名为 Dockerfile_runtime
FROM python:3
RUN pip install flask
2
再构建一下这个镜像,镜像名为 demo_runtime,默认 tag 是 latest
docker build . -t "demo_runtime" -f Dockerfile_runtime
这个时候,两个镜像都已准备好
# 2.3 容器编排
创建 deployments.yaml 文件,在 Pod 中的 initContainers 中配置代码镜像, 然后挂载临时存储卷,将代码复制到存储卷中。
然后再配置应用容器 python 运行环境,挂载上面相同的临时存储卷,然后再使用 python 将代码运行。
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo
labels:
app: demo
spec:
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
initContainers:
- image: demo_code:latest
name: code
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /opt/demo
name: app-volume
command: ["cp", "/main.py", "/opt/demo/"]
containers:
- name: runtime
image: demo_runtime:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
hostPort: 5000
protocol: TCP
name: http
volumeMounts:
- mountPath: /opt/demo
name: app-volume
command: ["python", "/opt/demo/main.py"]
volumes:
- name: app-volume
emptyDir: { }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
我们通过 kubectl apply
创建 deployments
kubectl apply -f deployments.yaml
我们通过 kubectl get pods 可以看到 pod 已经创建成功,然后找到 pod 所在的节点。通过节点 ip+端口即可访问到容器的中接口。
[root@k8s-master-07rf9 test]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
demo-6f49db5d6c-25vss 1/1 Running 0 4m58s 10.244.132.130 k8s-master-07rf9 <none> <none>
[root@k8s-master-07rf9 test]# curl 10.65.132.187:5000
Hello, World!
2
3
4
5
6
7
# 3. 总结
本文的编排方式只是 pod 的设计模式的一种。有兴趣的可以了解更多。
通过这种方式可以让代码与运行环境解耦,当我们更新代码时,并不会影响到运行环境。