k8s实验三 用服务实现应用互访
目录
本实验将创建2个 Nginx(版本 1.19.0) 应用,用域名的方式实现2个 Pod 互相访问的功能。
如果是用 docker 实现
常用 docker-compose 配置多个应用,同一网络内的应用可以根据服务名称互相访问。
docker-compose.yaml
version: '3'
services:
nginx1:
container_name: example3nginx1
image: nginx:1.19.0
nginx2:
container_name: example3nginx2
image: nginx:1.19.0
上面的 docker-compose 例子没有指定网络,docker-compose 会自动生成网络。
检查运行结果
# 去 nginx1 访问 nginx2
docker exec example3nginx1 curl nginx2
# 去 nginx2 访问 nginx1
docker exec example3nginx2 curl nginx1
现在在 k8s 上试运行,现在每个步骤都有配置文件,直接 kubectl apply -f <配置文件>
即可,故标题不再重复,具体请参考前几个实验。
创建 ConfigMap,存储键值对(key-value)数据
在 docker 部署应用经常需要环境变量(ENV),但是 ENV 有时候不是写死的,所以 docker-compose 创建服务时会读取 .env
文件,这个 .env
就是一个简单的键值对(key-value)文件。
k8s 提供一个更多功能的键值对,称 ConfigMap。像卷一样,ConfigMap 也要提前创建。
# Source configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: example3configmap
data:
example3_nginx1_myenv: nginx1_MY_ENV_VALUE
example3_nginx2_myenv: nginx2_MY_ENV_VALUE
nginx1_default.conf: |
server {
listen *:80;
server_name default_server;
location / {
return 200 'Nginx1';
}
}
nginx2_default.conf: |
server {
listen *:80;
server_name default_server;
location / {
return 200 'Nginx2';
}
}
# Source configmap.yaml
# 解析配置文件的版本,v1即可
apiVersion: v1
# 资源的类型,ConfigMap
kind: ConfigMap
# 元数据
metadata:
# 名称
name: example3configmap
# 键值对数据
data:
# 键值对 example3_nginx1_myenv: nginx1_MY_ENV_VALUE
example3_nginx1_myenv: nginx1_MY_ENV_VALUE
# 键值对 example3_nginx2_myenv: nginx2_MY_ENV_VALUE
example3_nginx2_myenv: nginx2_MY_ENV_VALUE
# 键值对 nginx1_default.conf,值可以是多行的,可以理解成文件内容,作为应用 nginx1 的配置文件
nginx1_default.conf: |
server {
listen *:80;
server_name default_server;
location / {
return 200 'Nginx1';
}
}
# 同上,作为应用 nginx2 的配置文件
nginx2_default.conf: |
server {
listen *:80;
server_name default_server;
location / {
return 200 'Nginx2';
}
}
详细字段说明
apiVersion
解析配置文件的版本,v1
即可。kind
资源的类型,ConfigMap。metadata
资源的元数据。metadata.name
ConfigMap 的名称。data
ConfigMap 定义键值对数据。data.example3_nginx1_myenv
定义键值对example3_nginx1_myenv
,值为nginx1_MY_ENV_VALUE
。data.example3_nginx2_myenv
同上,定义键值对example3_nginx2_myenv
,值为nginx2_MY_ENV_VALUE
。data.nginx1_default.conf
定义键值对nginx1_default.conf
,值可以是多行的,可以理解成文件内容。data.nginx2_default.conf
定义键值对nginx2_default.conf
,同上,这两个文件将作为 nginx 的配置文件。
检查运行结果
kubectl get configmap
kubectl describe configmap example3configmap
ConfigMap 的一个特点是可以将值映射成文件内容,而 docker 要在本机编写好文件,再用卷映射到容器(当然 docker 也可以用 echo 的方法输出文件,但是遇到多行内容会麻烦)。接下来的步骤会展示 ConfigMap 的使用方法。
创建 Nginx 1号应用,访问返回 Nginx1,配置文件取自 ConfigMap
# Source: pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: example3nginx1
labels:
app: example3nginx1
spec:
containers:
- name: example3nginx1
image: nginx:1.19.0
imagePullPolicy: IfNotPresent
env:
- name: MY_ENV_FROM_VALUE
value: i_am_from_value
- name: MY_ENV_FROM_CONFIG
valueFrom:
configMapKeyRef:
name: example3configmap
key: example3_nginx1_myenv
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: example3nginx1volume
readOnly: true
volumes:
- name: example3nginx1volume
configMap:
name: example3configmap
items:
- key: 'nginx1_default.conf'
path: 'default.conf'
# Source: pod1.yaml
# v1
apiVersion: v1
# 资源类型,Pod
kind: Pod
# 元数据
metadata:
# Pod 名称
name: example3nginx1
# Pod 标签
labels:
# 自定义 Pod 标签 app: example3nginx1
app: example3nginx1
# Pod 描述
spec:
# 运行哪些容器
containers:
# 容器名
- name: example3nginx1
# 容器镜像
image: nginx:1.19.0
# 镜像拉取策略
imagePullPolicy: IfNotPresent
# 容器环境变量
env:
# 定义环境变量 MY_ENV_FROM_VALUE="i_am_from_value"
- name: MY_ENV_FROM_VALUE
value: i_am_from_value
# 定义环境变量 MY_ENV_FROM_CONFIG,变量值取自 ConfigMap 的数据 example3_nginx1_myenv
- name: MY_ENV_FROM_CONFIG
valueFrom:
configMapKeyRef:
name: example3configmap
key: example3_nginx1_myenv
# 挂载临时卷
volumeMounts:
# 挂载一个临时卷 example3nginx1volume,挂载至容器路径 /etc/nginx/conf.d
- name: example3nginx1volume
mountPath: /etc/nginx/conf.d
readOnly: true # 只读
# 临时卷
volumes:
# 创建一个临时卷 example3nginx1volume
- name: example3nginx1volume
# 将 ConfigMap 的数据映射为文件
configMap:
name: example3configmap
items:
# 映射键 nginx1_default.conf,保存至文件 default.conf,存放到临时卷
- key: 'nginx1_default.conf'
path: 'default.conf'
详细字段说明
apiVersion
v1。kind
Pod。metadata
元数据。metadata.name
Pod 名称。labels
Pod 标签。labels.app
定义 Pod 标签app
,值为example3nginx1
,创建服务时,会根据这个标签找到这个Pod。spec
Pod 参数。spec.containers
定义 Pod 运行哪些容器。spec.containers.name
容器名。spec.containers.image
容器镜像。spec.containers.imagePullPolicy
镜像拉取策略,IfNotPresent
表示没有镜像时再去拉取。spec.containers.env
定义容器环境变量(ENV)。spec.containers.env.name
环境变量名。spec.containers.env.value
环境变量的值。spec.containers.env.valueFrom.configMapKeyRef
声明该环境变量的值来自 ConfigMap。spec.containers.env.valueFrom.configMapKeyRef.name
ConfigMap 的名称。spec.containers.env.valueFrom.configMapKeyRef.key
ConfigMap 的键,k8s 会根据键得到值。spec.containers.volumeMounts
配置临时卷的绑定关系。spec.containers.volumeMounts.mountPath
临时卷挂载点。spec.containers.volumeMounts.name
临时卷名称。spec.containers.volumeMounts.readOnly
声明临时卷只读。spec.volumes
声明临时卷。spec.volumes.name
临时卷名称。spec.volumes.configMap
声明临时卷的部分文件来自 ConfigMap。spec.volumes.configMap.name
ConfigMap 的名称。spec.volumes.configMap.items
配置从 ConfigMap 中映射出来的文件。spec.volumes.configMap.items.key
ConfigMap 键。spec.volumes.configMap.items.path
该往哪个文件放入值,default.conf
是 Nginx 默认配置文件,加上挂载点后的目录就是<挂载点>/<文件名>
。
现在定义了一个 Pod,配置文件是从 ConfigMap 获取的,根据键 nginx1_default.conf
去查 ConfigMap,可以得到 Nginx 配置文件:
# 这个内容来自 ConfigMap -> nginx1_default.conf
# 将被挂载到 /etc/nginx/conf.d,文件名 default.conf
server {
listen *:80;
server_name default_server;
location / {
return 200 'Nginx1';
}
}
这份 Nginx 配置文件简单描述了 「访问根目录时,返回字符串 “Nginx1”」。现在可以先部署这个 Pod。
为这个 Pod 创建服务 (Service)
kind: Service
metadata:
name: example3nginx1svc
spec:
type: ClusterIP
selector:
app: example3nginx1
ports:
- port: 80
targetPort: 80
# Source: pod1svc.yaml
kind: Service
metadata:
name: example3nginx1svc
spec:
# 端口映射类型,ClusterIP(集群内网访问)
type: ClusterIP
# 标签过滤
selector:
# 带有标签 app: example3nginx1 的 Pod 会被映射端口
app: example3nginx1
# 端口配置
ports:
# 内网访问端口
- port: 80
# Pod 中的端口
targetPort: 80
Service 字段简单说明
这份服务配置文件相对简单了,它的工作是找到标签 app = example3nginx1
的 Pod,然后给它提供内网端口映射。具体的字段在之前的实验已经描述过了,简单说一下吧:
spec
Service 的参数。spec.ports
Service 需要映射的端口。spec.ports.port
内网映射出来的端口。spec.ports.targetPort
Pod 的端口,注意不要和port
搞混。
现在把这个服务部署起来。
服务可以为 Pod 提供 DNS 记录
当这个服务和 Nginx1 Pod 绑定成功后,其他 Pod 都可以通过域名访问到该 Pod 了(亲测其他 namespace 也可以)。
域名格式: <Service名>.<Namespace名>.svc.<节点域名>
<Service名>
服务的名称,上方的服务名为example3nginx1svc
。<Namespace名>
命名空间,可用kubectl get namespaces
查看,没有提及命名空间的都是default
。<集群域名>
k8s 集群域名,可以进 Pod 查看(kubectl exec example3nginx1 -- cat /etc/resolv.conf
),一般是cluster.local
。
按照格式组装好的域名是: example3nginx1svc.default.svc.cluster.local
,带这个域名进入 Pod 解析并发起请求,可以得到结果 Nginx1
:
kubectl exec example3nginx1 -- curl example3nginx1svc.default.svc.cluster.local
不过这个是在自己的 Pod 下面执行的,对于是否可以在其他应用下调用到 Nginx1 应用,请继续往下看。
创建 Nginx 2号应用,访问返回 Nginx2,配置文件也取自 ConfigMap,并配置服务
和上面 Pod 和 Service 的配置一样,只是名字和标签修改了而已。具体的字段说明就不一一列出了,但请注意加 #
号,会展示与 Nginx1号 配置不一样的地方。
另外 k8s yaml 支持在一个文件中配置多个资源对象,之间用新一行 ---
隔开。
# 源文件: pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: example3nginx2 #
labels:
app: example3nginx2 #
spec:
containers:
- name: example3nginx2 #
image: nginx:1.19.0
imagePullPolicy: IfNotPresent
env:
- name: MY_ENV_FROM_VALUE
value: i_am_from_value
- name: MY_ENV_FROM_CONFIG
valueFrom:
configMapKeyRef:
name: example3configmap
key: example3_nginx2_myenv #
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: example3nginx2volume #
readOnly: true
volumes:
- name: example3nginx2volume #
configMap:
name: example3configmap
items:
- key: 'nginx2_default.conf' #
path: 'default.conf'
---
# 源文件: pod2svc.yaml
# 给 Nginx2号 应用配置服务
kind: Service
metadata:
name: example3nginx2svc #
spec:
type: ClusterIP
selector:
app: example3nginx2 #
ports:
- port: 80
targetPort: 80
直接启动,k8s 将创建2个资源对象:
- Pod对象,名称 example3nginx2。
- Service对象,名称 example3nginx2svc。
验证互访
Nginx1、Nginx2 的 Pod 已经部署好了,并且各自都配置了服务,那么总结出2个服务的 DNS 记录。
服务概览
应用 | Pod名称 | 服务名称 | 域名 |
---|---|---|---|
Nginx1 | example3nginx1 | example3nginx1svc | example3nginx1svc.default.svc.local |
Nginx2 | example3nginx2 | example3nginx2svc | example3nginx2svc.default.svc.local |
互相进入 Pod,访问对方
进入 Nginx1,访问 Nginx2
kubectl exec example3nginx1 -- curl example3nginx2svc.default.svc.local
# 获得响应 Nginx2
进入 Nginx2,访问 Nginx1
kubectl exec example3nginx2 -- curl example3nginx1svc.default.svc.local
# 获得响应 Nginx1
预期结果无误,那么实验顺利结束了。
清理部署资源
本次实验用的资源比较多,下面一一列举出来:
资源 | kind | 名称(name) | 通过名称删除 |
---|---|---|---|
键值对配置 | ConfigMap | example3configmap | kubectl delete configmap example3configmap |
Nginx1应用 | Pod | example3nginx1 | kubectl delete pod example3nginx1 |
Nginx2应用 | Pod | example3nginx2 | kubectl delete pod example3nginx2 |
Nginx1服务 | Service | example3nginx1svc | kubectl delete svc example3nginx1svc |
Nginx2服务 | Service | example3nginx2svc | kubectl delete svc example3nginx2svc |