06.Kubernetes Secret和Kubernetes Controllers
2026-04-23
复习和预习
昨天课堂内容
- Volume
- ConfigMap
- 部署一个自己网站。
课前复习
默写
今天课堂内容
- secrets
- rs
- deployment
Kubernetes Secret
环境准备
[root@master30 ~]# kubectl create ns secret
[root@master30 ~]# kubectl config set-context --current --namespace secret
Secret
学习参考:Secret
Secret 介绍
Secret 是一种包含少量敏感信息的对象,例如密码、令牌或密钥。 这样的信息可能会被放在 Pod 规约中或者镜像中。 使用 Secret 意味着你不需要在应用程序代码中包含机密数据。
创建 Secret 可以独立于使用它们的 Pod, 减少在创建、查看和编辑 Pod 的工作流程中暴露 Secret(及其数据)的风险。 Kubernetes 和在集群中运行的应用程序也可以对 Secret 采取额外的预防措施, 例如避免将敏感数据写入非易失性存储。
Secret 类似于 ConfigMap 但专门用于保存机密数据。
Secret 与ConfigMap的区别在于:Secret对数据编码,ConfigMap不对数据编码。
Secret 类型
-
generic:定义键值对,对变量值加密,类型为Opaque。
-
docker-registry:用于访问registry仓库的凭据,类型kubernetes.io/dockerconfigjson。
-
tls:保存TLS公钥和私钥,类型为Opaque。
Secret 创建
generic
# 帮助信息
[root@master30 ~]# kubectl create secret generic --help
Create a secret based on a file, directory, or specified literal value.
A single secret may package one or more key/value pairs
......
基于键值对
一般用于传递变量值。
[root@master30 ~]# kubectl create secret generic mysecret1 --from-literal=user=tom --from-literal=password1=redhat --from-literal=password2=redhat
[root@master30 ~]# kubectl get secrets
NAME TYPE DATA AGE
mysecret1 Opaque 3 21s
[root@master30 ~]# kubectl get secrets mysecret1 -o yaml
apiVersion: v1
data:
password1: cmVkaGF0
password2: cmVkaGF0
user: dG9t
kind: Secret
metadata:
......
name: mysecret1
namespace: laoma
resourceVersion: "24180"
selfLink: /api/v1/namespaces/laoma/secrets/mysecret1
uid: d510d58f-8737-4d2f-bd00-dd9ce6b50a9b
type: Opaque
[root@master30 ~]# kubectl get secrets mysecret1 -o jsonpath={.data} | json_reformat
{
"password1": "cmVkaGF0",
"password2": "cmVkaGF0",
"user": "amFjaw=="
}
# json_reformat 工具由软件包 yajl-tools 提供
[root@master30 ~]# kubectl get secrets mysecret1 -o jsonpath={.data.user}
amFjaw==
[root@master30 ~]# kubectl describe secrets mysecret1
Name: mysecret1
Namespace: laoma
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password1: 6 bytes
password2: 6 bytes
user: 3 bytes
# secret 通过 base64 编码
[root@master30 ~]# echo -n tom | base64
dG9t
[root@master30 ~]# echo -n redhat|base64
cmVkaGF0
[root@master30 ~]# echo -n cmVkaGF0|base64 -d
redhat
基于普通文件
一般用于传递配置文件。
[root@master30 ~]# echo -n tom > user
[root@master30 ~]# echo -n redhat > password1
[root@master30 ~]# echo -n redhat > password2
[root@master30 ~]# kubectl create secret generic mysecret2 --from-file=./user --from-file=./password1 --from-file=./password2
# 文件名用作key名,文件内容用作value,也可以自定义key名
[root@master30 ~]# kubectl create secret generic mysecret3 --from-file=username=./user --from-file=./password1 --from-file=./password2
[root@master30 ~]# kubectl get secrets mysecret2 -o yaml
apiVersion: v1
data:
password1: cmVkaGF0
password2: cmVkaGF0
user: dG9t
kind: Secret
metadata:
......
name: mysecret2
namespace: laoma
resourceVersion: "25329"
selfLink: /api/v1/namespaces/laoma/secrets/mysecret2
uid: 047366b6-e8d2-4cf0-b68c-d1f5f9999458
type: Opaque
[root@master30 ~]# kubectl get secrets mysecret3 -o yaml
apiVersion: v1
data:
password1: cmVkaGF0
password2: cmVkaGF0
username: dG9t
kind: Secret
metadata:
......
name: mysecret3
namespace: laoma
resourceVersion: "25532"
selfLink: /api/v1/namespaces/laoma/secrets/mysecret3
uid: e19df9a7-7ce3-4539-b6f5-92f83417ac1f
type: Opaque
基于键值对内容的文件
[root@master30 ~]# echo 'user=tom
password1=redhat
password2=redhat' > env.txt
[root@master30 ~]# kubectl create secret generic mysecret4 --from-env-file=./env.txt
secret/mysecret4 created
[root@master30 ~]# kubectl get secrets mysecret4 -o yaml
apiVersion: v1
data:
password1: cmVkaGF0
password2: cmVkaGF0
user: dG9t
kind: Secret
metadata:
......
name: mysecret5
namespace: laoma
resourceVersion: "27240"
selfLink: /api/v1/namespaces/laoma/secrets/mysecret3
uid: 935c0392-8e54-492d-b093-99021e0dc5bb
type: Opaque
基于目录
文件名用作key名,文件内容用作value。
[root@master30 ~]# mkdir secrets
[root@master30 ~]# mv user password1 password2 secrets
[root@master30 ~]# kubectl create secret generic mysecret5 --from-file=./secrets
secret/my-secret5 created
[root@master30 ~]# kubectl get secrets mysecret5 -o yaml
apiVersion: v1
data:
password1: cmVkaGF0
password2: cmVkaGF0
user: dG9t
kind: Secret
metadata:
......
name: mysecret5
namespace: laoma
resourceVersion: "26687"
selfLink: /api/v1/namespaces/laoma/secrets/mysecret4
uid: 04eccd8b-8686-4856-82c3-0ac697d75746
type: Opaque
基于 yaml 文件
apiVersion: v1
kind: Secret
metadata:
name: mysecret6
type: Opaque
data:
user: dG9t
password1: cmVkaGF0
password2: cmVkaGF0
yaml格式中变量值使用转换后的值。
docker-registry
回顾docker login命令:
docker login DOCKER_REGISTRY_SERVER -u=DOCKER_USER -p=DOCKER_PASSWORD
docker 登录的信息默认保存在~/.dockercfg,后续docker pull和push使用该凭据文件访问registry。
Usage:
kubectl create secret docker-registry NAME --docker-username=user --docker-password=password --docker-email=email [--docker-server=string] [--from-literal=key1=value1] [--dry-run=server|client|none] [options]
示例:
[root@master30 ~]# kubectl create secret docker-registry registry --docker-username=laoma --docker-password=redhat --docker-email=laoma@laoma.cloud --docker-server=registry.laoma.cloud
secret/docker-registry-secret created
[root@master30 ~]# kubectl get secrets docker-registry-secret -o yaml
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6eyJyZWdpc3RyeS5yZWRoYXQuZnVuIjp7InVzZXJuYW1lIjoibGFvbWEiLCJwYXNzd29yZCI6InJlZGhhdCIsImVtYWlsIjoibGFvbWFAcmVkaGF0LmZ1biIsImF1dGgiOiJiR0Z2YldFNmNtVmthR0YwIn19fQ==
kind: Secret
metadata:
......
name: docker-registry-secret
namespace: laoma
resourceVersion: "29629"
selfLink: /api/v1/namespaces/laoma/secrets/docker-registry-secret
uid: 017f736a-11f5-42d8-a9ed-47dad254f2c2
type: kubernetes.io/dockerconfigjson
TLS
创建 TLS secret 保存公钥/私钥对。 公钥证书必须是 .PEM 编码。
Usage:
kubectl create secret tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run=server|client|none] [options]
创建私钥和证书
#--1--生成私钥
[root@master30 ~]# mkdir certs && cd certs
[root@master30 certs]# openssl genrsa -out www.key 2048
#--2--生成请求文件csr
[root@master30 certs]# openssl req -new -key www.key -out www.csr -subj "/C=CN/ST=JS/L=NJ/O=LM/OU=DEVOPS/CN=www.laoma.cloud/emailAddress=webadmin@laoma.cloud"
# CN的值必须是网站域名
#--3--使用自己的私钥对请求文件签名,以生成证书
[root@master30 certs]# openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt
创建 tls 类型secret
[root@master30 certs]# kubectl create secret tls www-tls --cert=./www.crt --key=./www.key
Secret 引用
Secrets可以以卷方式挂载给pods,也可以通过环境变量方式传递给pods。
以环境变量方式引用
示例:
[root@master30 ~]# vim pod-secret-env.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
name: mysql
spec:
containers:
- image: docker.io/library/mysql:latest
imagePullPolicy: IfNotPresent
name: mysql
ports:
- containerPort: 3306
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
# 原先通过value设置环境变量值
valueFrom:
secretKeyRef:
name: mysecret1
key: password1
验证
[root@master30 ~]# kubectl apply -f pod-secret-env.yaml
[root@master30 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql 1/1 Running 0 90s 10.224.51.131 worker31.laoma.cloud <none> <none>
[root@master30 ~]# kubectl exec -it mysql -- bash -c 'echo $MYSQL_ROOT_PASSWORD'
redhat
[root@master30 ~]# mysql -u root -predhat -h 10.224.51.131
# 清理pod
[root@master30 ~]# kubectl delete pod mysql --force
以 volume 方式引用
[root@master30 ~]# echo Hello world > index.html
[root@master30 ~]# echo error > error.html
[root@master30 ~]# kubectl create secret generic web --from-file=./index.html --from-file=./error.html
引用整体
示例:
[root@master30 ~]# vim pod-secret-volume-all.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: web
name: web
spec:
containers:
- image: docker.io/library/nginx:latest
imagePullPolicy: IfNotPresent
name: web
volumeMounts:
- name: webcontent
# mountPath值是一个挂载点,将secrete中所有键值对挂载过来
mountPath: "/usr/share/nginx/html"
volumes:
- name: webcontent
secret:
secretName: web
验证
[root@master30 ~]# kubectl apply -f pod-secret-volume-all.yaml
[root@master30 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web 1/1 Running 0 15s 10.224.51.136 worker31.laoma.cloud <none> <none>
[root@master30 ~]# curl 10.224.51.136
Hello World
[root@master30 ~]# curl 10.224.51.136/error.html
error
# 清理pod
[root@master30 ~]# kubectl delete pod web --force
引用特定 key
示例:nginx.yaml
[root@master30 ~]# vim pod-secret-volume-single.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: web
name: web
spec:
containers:
- image: docker.io/library/nginx:latest
imagePullPolicy: IfNotPresent
name: web
volumeMounts:
- name: webcontent
mountPath: "/usr/share/nginx/html"
volumes:
- name: webcontent
secret:
secretName: web
items:
- key: index.html
# 通过path设置挂载的文件名,这里我们path值与key一致。
path: index.html
或者
apiVersion: v1
kind: Pod
metadata:
labels:
run: web
name: web
spec:
containers:
- image: docker.io/library/nginx:latest
imagePullPolicy: IfNotPresent
name: web
volumeMounts:
- name: webcontent
# 将webcontent中index.html挂载到/usr/share/nginx/html/index.html
mountPath: "/usr/share/nginx/html/index.html"
# 使用subPath参数,则表明mountPath的值是一个文件
subPath: index.html
volumes:
- name: webcontent
secret:
secretName: web
验证
[root@master30 ~]# kubectl create -f pod-secret-volume-single.yaml
[root@master30 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web 1/1 Running 0 21s 10.224.51.137 worker31.laoma.cloud <none> <none>
[root@master30 ~]# curl 10.224.51.137/index.html
Hello World
# /usr/share/nginx/html目录中没有index.html和error.html
[root@master30 ~]# kubectl exec web -- ls /usr/share/nginx/html
index.html
以卷方式引用,支持动态更新secret内容:
[root@master30 ~]# echo 'Hello Nginx' |base64
SGVsbG8gbmdpbng=
# 更改data.index内容为SGVsbG8gbmdpbng=
[root@master30 ~]# kubectl edit secrets web
......
apiVersion: v1
data:
index: SGVsbG8gbmdpbng=
......
# 等30秒左右查看
[root@master30 ~]# curl 10.224.51.137/index.html
Hello Nginx
文件权限
映射过去文件默认权限是644(8进制),对应10进制是420.。
设置映射的所有文件权限,defaultMode。
volumes:
- name: foo
secret:
secretName: mysecret1
defaultMode: 256
10进制是256转换成8进制是400。因为json格式不支持8进制,所以使用10进制。
[root@master30 ~]# kubectl exec mypod1 -- ls -l /etc/foo/..data/user
-r-------- 1 root root 4 Aug 9 08:58 /etc/foo/..data/user
设置映射的单独文件权限
volumes:
- name: foo
secret:
secretName: mysecret1
items:
- key: user
path: user
mode: 511
10进制是511转换成8进制是777。
[root@master30 ~]# kubectl exec mypod1 -- ls -l /etc/foo/..data/user
-rwxrwxrwx 1 root root 4 Aug 9 08:58 /etc/foo/..data/user
综合实验
实验要求
基于LNMP架构部署blog应用。
具体要求如下:
- 使用mysql、php-fpm、nginx镜像和wordpress-4.9.4-zh_CN.zip文件部署blog应用。
- blog应用通过https访问。
- 密码和站点证书用secret存储。
- 站点 vhost 配置使用configmap提供。
提示:php-fpm 镜像找老师获取。
实验步骤
部署 mysql
[root@master30 ~]# kubectl create secret generic mysql --from-literal user=tom --from-literal password_for_user=redhat --from-literal password_for_root=redhat --from-literal db_name=wordpress
[root@master30 certs]# kubectl get secrets mysql
NAME TYPE DATA AGE
mysql Opaque 4 17s
[root@master30 ~]# vim pod-mysql-secret.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
name: mysql
spec:
containers:
- image: docker.io/library/mysql:latest
imagePullPolicy: IfNotPresent
name: mysql
ports:
- containerPort: 3306
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql
key: password_for_root
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: mysql
key: user
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql
key: password_for_user
- name: MYSQL_DATABASE
valueFrom:
secretKeyRef:
name: mysql
key: db_name
[root@master30 ~]# kubectl apply -f pod-mysql-secret.yaml
[root@master30 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql 1/1 Running 0 3s
[root@master30 ~]# kubectl exec -it mysql -- mysql -utom -predhat -e "show databases;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| information_schema |
| performance_schema |
| wordpress |
+--------------------+
部署 php-fpm
部署 nginx
创建私钥和证书
#--1--生成私钥
[root@master30 ~]# mkdir certs && cd certs
[root@master30 certs]# openssl genrsa -out blog.key 2048
#--2--生成请求文件csr
[root@master30 certs]# openssl req -new -key blog.key -out blog.csr -subj "/C=CN/ST=JS/L=NJ/O=LM/OU=DEVOPS/CN=blog.laoma.cloud/emailAddress=webadmin@laoma.cloud"
# CN的值必须是网站域名
#--3--使用自己的私钥对请求文件签名,以生成证书
[root@master30 certs]# openssl x509 -req -days 3650 -in blog.csr -signkey blog.key -out blog.crt
创建 tls 类型secret
[root@master30 certs]# kubectl create secret tls blog-tls --cert=./blog.crt --key=./blog.key
[root@master30 certs]# kubectl get secrets blog-tls
NAME TYPE DATA AGE
blog-tls kubernetes.io/tls 2 25s
准备虚拟主机配置文件
[root@master30 ~]# vim default-ssl.conf
<VirtualHost *:443>
DocumentRoot /var/www/html
SSLEngine On
SSLCertificateFile /etc/apache2/ssl/tls.crt
SSLCertificateKeyFile /etc/apache2/ssl/tls.key
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
[root@master30 ~]# kubectl create configmap blog-ssl-config --from-file=./default-ssl.conf
准备pod-wordpress
apiVersion: v1
kind: Pod
metadata:
name: wordpress
labels:
run: wordpress
spec:
volumes:
- name: blog-tls
secret:
secretName: blog-tls
- name: blog-ssl-config
configMap:
name: blog-ssl-config
containers:
- image: wordpress:latest
imagePullPolicy: IfNotPresent
name: wordpress
command: ["/bin/bash", "-c"]
args:
- |
a2enmod ssl;
cp -a /usr/src/wordpress/* /var/www/html;
apache2-foreground;
volumeMounts:
- name: blog-tls
mountPath: /etc/apache2/ssl
readOnly: true
- name: blog-ssl-config
mountPath: "/etc/apache2/sites-enabled/default-ssl.conf"
subPath: default-ssl.conf
env:
- name: WORDPRESS_DB_USER
valueFrom:
secretKeyRef:
name: mysql
key: user
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql
key: password_for_user
- name: WORDPRESS_DB_NAME
valueFrom:
secretKeyRef:
name: mysql
key: db_name
- name: WORDPRESS_DB_HOST
value: "10.224.113.130"
ports:
- containerPort: 80
- containerPort: 443
部署 wordpress
kubectl get all
all不是所有资源,而是 Kubernetes 定义的一组 “常用核心资源”
包含:工作负载 + Service
all 包含的资源列表(固定 7 类)
1. pods # Pod
2. replicationcontrollers # RC (很少用)
3. services # Service
4. daemonsets # DaemonSet
5. deployments # Deployment
6. replicasets # ReplicaSet
7. statefulsets # StatefulSet
下面这些都不在 all 里,必须单独 get:
- configmaps (cm) ⚠️ 不在 all 里
- secrets (secret) ⚠️ 不在 all 里
- ingress (ing) ⚠️ 不在 all 里
- persistentvolumes (pv) ⚠️
- persistentvolumeclaims (pvc) ⚠️
- endpoints (ep) ⚠️
- events (ev) ⚠️
- jobs
- cronjobs
- roles / clusterroles
- serviceaccounts
- hpa
查看真正的 “所有资源”
kubectl get all,cm,secret,pvc,ingress
环境清理
[root@master30 ~]# kubectl delete ns secret
Kubernetes Controllers
学习参考:控制器
环境准备
[root@master30 ~]# kubectl create ns controllers
[root@master30 ~]# kubectl config set-context --current --namespace controllers
Controllers 介绍
Controller 主要作用是确保所管理的资源处于用户期望的状态,通过不断地监控资源的状态,并根据实际状态与期望状态之间的差异执行相应的动作,来实现资源的自愈、自动扩展等功能。
先简单回顾一下:容器按照是否持续运行可分为两类。
-
服务类容器: 一直运行任务,通常持续提供服务, 比如HTTP等。
-
工作类容器:一次性任务, 比如批处理程序,完成后容器就退出。
Kubernetes 中用于管理服务类容器的控制器有 ReplicaSet 、Deployment 和 DaemonSet 等。
Kubernetes 中用于管理工作类容器的控制器有 Job 和 CronJob。
ReplicaSets
学习参考:ReplicaSets。
ReplicaSets 介绍
ReplicaSet,简称RS,是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。
ReplicaSet 工作原理
ReplicaSet 部分主要字段:
- 一个用来识别可获得的 Pod 的集合的选择算符。
- 一个用来标明应该维护的副本个数的数值。
- 一个用来指定创建新 Pod 时要使用的 Pod 模板。
每个 ReplicaSet 根据 Pod 模板创建制定数量 Pod, 进而实现其存在价值。
- 如果pod数量多于指定数量,则RS会终止额外的pod。
- 如果pod数量少于指定数量,则RS会创建额外的pod。例如宿主机内核升级,在其他节点上创建新Pod。
ReplicaSet 使用
ReplicaSet 创建
[root@master30 ~]# vim rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: docker.io/library/nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
[root@master30 ~]# kubectl apply -f rs.yaml
[root@master30 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx 3 3 3 8m45s
[root@master30 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-95pth 1/1 Running 0 8m48s
nginx-9jg4f 1/1 Running 0 8m48s
nginx-tjtp2 1/1 Running 0 8m48s
[root@master30 ~]# kubectl describe pod nginx-9jg4f |grep Controlled
Controlled By: ReplicaSet/nginx
ReplicaSet 健壮性测试
测试1:删除单个副本
[root@master30 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx 3 3 3 8m45s
[root@master30 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-95pth 1/1 Running 0 8m48s
nginx-9jg4f 1/1 Running 0 8m48s
nginx-tjtp2 1/1 Running 0 8m48s
# 删除一个pod
[root@master30 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-95pth 1/1 Running 0 8m48s
nginx-9jg4f 1/1 Running 0 8m48s
nginx-tjtp2 1/1 Running 0 8m48s
[root@master30 ~]# kubectl delete pod nginx-95pth --force
[root@master30 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-4qw2z 1/1 Running 0 2s
nginx-9jg4f 1/1 Running 0 9m20s
nginx-tjtp2 1/1 Running 0 9m20s
Pod 的 metadata.ownerReferences 字段,显示所属主资源。 正是通过这一连接,ReplicaSet 知道它所维护的 Pod 集合的状态, 并据此计划其操作行为。
ReplicaSet 使用 selector 获得 Pod 集合。如果某个 Pod 没有 OwnerReference 或者其 OwnerReference 不是一个控制器, 且其匹配到某 ReplicaSet 的选择算符,则该 Pod 立即被此 ReplicaSet 获得。
测试2:创建具有相同标签的pod
[root@master30 ~]# kubectl run nginx --image=docker.io/library/nginx:latest -l app=nginx;kubectl get pods
pod/nginx created
NAME READY STATUS RESTARTS AGE
nginx 0/1 Terminating 0 0s
nginx-4qw2z 1/1 Running 0 3m40s
nginx-9jg4f 1/1 Running 0 12m
nginx-tjtp2 1/1 Running 0 12m
# 刚创建出来就被Terminating
ReplicaSet 删除
删除RS控制器,会删除它管理的pods。
[root@master30 ~]# kubectl delete rs nginx
[root@master30 ~]# kubectl get pods
使用**–cascade=orphan**选项,只删除RS,保留pod。
[root@master30 ~]# kubectl apply -f rs.yaml
[root@master30 ~]# kubectl delete rs nginx --cascade=orphan
[root@master30 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod/nginx-27vzb 1/1 Running 0 73s
pod/nginx-7lc95 1/1 Running 0 73s
pod/nginx-mmrhk 1/1 Running 0 73s
# 删除pod
[root@master30 ~]# kubectl delete all -l app=nginx
ReplicationController
ReplicationController,简称RC,功能与ReplicaSets类似。 ReplicaSet 是 RC 的升级版, 支持新的基于集合的标签选择算符。
这里我们不详细介绍ReplicationController。
Deployment
学习参考:Deployment
Deployment 介绍
Deployment,简称 deploy,为 Pod 和 ReplicaSet 提供声明式的更新能力。
ReplicaSet 能确保运行指定数量的pod。Deployment能管理ReplicaSets,并提供对pod的更新等功能。因此,我们建议你使用Deployment来管理ReplicaSets,除非你需要自定义更新编排。这意味着你可能永远不需要操作ReplicaSet对象,而是使用Deployment替代管理 。
Deployment 用例
以下是 Deployments 的典型用例:
-
创建 Deployment 以将 ReplicaSet 上线。检查 ReplicaSet 的上线状态,查看其是否成功。
-
通过更新 Deployment 的 PodTemplateSpec,声明 Pod 的新状态 。 新的 ReplicaSet 会被创建,Deployment 以受控速率将 Pod 从旧 ReplicaSet 迁移到新 ReplicaSet。 每个新的 ReplicaSet 都会更新 Deployment 的修订版本。
-
如果 Deployment 的当前状态不稳定,回滚到较早的 Deployment 版本。 每次回滚都会更新 Deployment 的修订版本。
-
暂停 Deployment 的上线 以应用对 PodTemplateSpec 所作的多项修改, 然后恢复其执行以启动新的上线版本。
-
使用 Deployment 状态来判定上线过程是否出现停滞。
Deployment 管理
创建
命令行方式
[root@master30 ~]# kubectl create deployment web --image=docker.io/library/nginx:1.27 --replicas=2
# 查看deployment创建的资源
[root@master30 ~]# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/web-b78cbd74b-6fjxs 1/1 Running 0 3s
pod/web-b78cbd74b-mh6fh 1/1 Running 0 3s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/web 2/2 2 2 3s
NAME DESIRED CURRENT READY AGE
replicaset.apps/web-b78cbd74b 2 2 2 3s
# 查看deployment详细信息
[root@master30 ~]# kubectl describe deployments.apps web
Name: web
Namespace: laoma
CreationTimestamp: Sat, 21 Oct 2023 13:17:06 +0000
Labels: app=web
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=web
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=web
Containers:
nginx:
Image: nginx:1.27
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: web-b78cbd74b (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 21s deployment-controller Scaled up replica set web-b78cbd74b to 2
# ReplicaSet与Deployment关系
[root@master30 ~]# kubectl describe replicaset.apps web-b78cbd74b | grep Controlled
Controlled By: Deployment/web
# 指明ReplicaSet是由Deployment/web创建的。
# pod与ReplicaSet关系
[root@master30 ~]# kubectl describe pod web-b78cbd74b-6fjxs | grep Controlled
Controlled By: ReplicaSet/web-b78cbd74b
# 指明pod是由ReplicaSet/web-b78cbd74b创建的。
yaml 文件方式
# 获取deployment的yaml文件
[root@master30 ~]# kubectl create deployment web --image=docker.io/library/nginx:1.27 --replicas=2 --dry-run=client -o yaml > deployment-web.yaml
[root@master30 ~]# cat deployment-web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
name: web
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- image: docker.io/library/nginx:1.27
name: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
格式说明:
① apiVersion,是当前配置格式的版本。
② kind,是要创建的资源类型, 这里是Deployment。
③ metadata,是该资源的元数据, name是必需的元数据项。
④ spec,是该Deployment的规格说明。
⑤ spec.replicas,指明副本数量, 默认为1。
⑥ spec.template,定义Pod的模板, 这是配置文件的重要部分。
⑦ spec.template.metadata,定义Pod的元数据, 至少要定义一个label。 label的key和value可以任意指定。
⑧ spec.template.spec,描述Pod的规格, 此部分定义Pod中每一个容器的属性,name和image是必需的。
[root@master30 ~]# kubectl apply -f deployment-web.yaml
创建方式进行比较
- 基于命令行的方式:
- 简单、 直观、 快捷, 上手快。
- 适合临时测试或实验。
- 基于配置文件的方式:
- 配置文件描述了What, 即应用最终要达到的状态。
- 配置文件提供了创建资源的模板, 能够重复部署。
- 可以像管理代码一样管理部署。
- 适合正式的、 跨环境的、 规模化部署。
- 这种方式要求熟悉配置文件的语法, 有一定难度。
**kubectl apply **命令不但能够创建Kubernetes资源, 也能对资源进行更新, 非常方便。
编辑
# 方法1:命令行直接修改
[root@master30 ~]# kubectl edit deployments.apps web
# 方法2:编辑资源文件,然后apply应用
# 方法3:命令行修改,例如修改deployment副本数
[root@master30 ~]# kubectl scale deployment web --replicas=4
删除
删除deployments时,默认会删除deployments管理的子资源。
[root@master30 ~]# kubectl delete deployments.apps web
deployment.apps "web" deleted
使用**–cascade=orphan选项**删除deployments,不会删除deployments管理的子资源。
[root@master30 ~]# kubectl apply -f deployment-web.yaml
[root@master30 ~]# kubectl delete deployments.apps web --cascade=orphan
# 先确山删除对象
[root@master30 ~]# kubectl get all -l app=web
# 然后再删除
[root@master30 ~]# kubectl delete all -l app=web
[root@master30 ~]# kubectl get all -l app=web
水平伸缩
# 创建 deployment
[root@master30 ~]# kubectl create deployment web --image=docker.io/library/nginx:1.27 --replicas=2
[root@master30 ~]# kubectl scale deployment web --replicas=3
# 或者
[root@master30 ~]# kubectl edit deployments.apps web
# 或者修改yaml文件并apply
[root@master30 ~]# kubectl get deployments.apps web -o yaml > web.yaml
[root@master30 ~]# vim web.yaml
[root@master30 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-5899d78c9-cckln 1/1 Running 0 9m28s
web-5899d78c9-p8pk4 1/1 Running 0 43s
web-5899d78c9-phntq 1/1 Running 0 9m28s
健壮性测试
关闭 worker节点,测试pod重建。
[root@master30 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-5899d78c9-cckln 1/1 Running 0 14m 10.224.51.134 worker31.laoma.cloud <none> <none>
web-5899d78c9-p8pk4 1/1 Running 0 6m12s 10.224.51.135 worker31.laoma.cloud <none> <none>
web-5899d78c9-phntq 1/1 Running 0 14m 10.224.225.69 worker32.laoma.cloud <none> <none>
# 关闭 worker32
[root@worker32 ~]# init 0
# 等待一段时间(5分钟), Kubernetes 判定 worker32不可用, 将worker32上的Pod标记为Unknown状态, 并在worker31上重建Pod,维持总副本数为3
# 当worker32恢复后, Unknown的Pod会被删除, 已经运行的Pod不会重新调度回worker32。
K8s 判断节点宕机,要经过 3 个阶段:
-
Node 节点上kubelet 默认 每 10s 发一次心跳上报自身状态(kubelet → kube-apiserver)
-
Master 上
controller-manager每 5 秒检查一次心跳,连续 40s 没收到 Node节点心跳,判定 Node 节点不健康,b标记为NotReady。参数:node-monitor-period=5s 和 node-monitor-grace-period=40s。
该参数属于 kube-controller-manager 组件,该组件以静态 Pod 形式运行在 master 节点,路径:
/etc/kubernetes/manifests/kube-controller-manager.yaml编辑静态 Pod 配置文件,找到
command段,添加或修改--pod-eviction-timeout参数,保存文件,触发静态 Pod 重启。 -
节点 NotReady 持续满 5 分钟,开始把 Pod 驱逐到别的节点。
参数:pod-eviction-timeout=300s。
该参数也属于 kube-controller-manager 组件,该组件以静态 Pod 形式运行在 master 节点。修改方法同上。
更新镜像
# 设置 deployment 的 image 为 docker.io/library/nginx:1.28
# 获取容器名称
[root@master30 ~]# kubectl get deployments.apps -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
web 3/3 3 3 139m nginx docker.io/library/nginx:1.27 app=web
# 或者
[root@master30 ~]# kubectl describe deployments.apps web |grep Container -i -A2
Containers:
nginx:
Image: docker.io/library/nginx:1.27
# 更新镜像为docker.io/library/nginx:1.28
[root@master30 ~]# kubectl set image deployment/web nginx=docker.io/library/nginx:1.28 --record
# 或者直接编辑deploy设置镜像
[root@master30 ~]# kubectl edit deployments.apps web
# 新增了一个replicaset,用于创建新的pod
[root@master30 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
replicaset.apps/web-5899d78c9 0 0 0 26m
replicaset.apps/web-6c57bdf5f4 3 3 3 9s
# 查看镜像版本
[root@master30 ~]# kubectl get deployments.apps web -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
web 3/3 3 3 26m nginx docker.io/library/nginx:1.28 app=web
版本控制
使用 kubectl rollout 命令控制deployment版本。
[root@master30 ~]# kubectl rollout -h
Manage the rollout of one or many resources.
Valid resource types include:
* deployments
* daemonsets
* statefulsets
Examples:
# Rollback to the previous deployment
kubectl rollout undo deployment/abc
# Check the rollout status of a daemonset
kubectl rollout status daemonset/foo
# Restart a deployment
kubectl rollout restart deployment/abc
# Restart deployments with the 'app=nginx' label
kubectl rollout restart deployment --selector=app=nginx
Available Commands:
history View rollout history
pause Mark the provided resource as paused
restart Restart a resource
resume Resume a paused resource
status Show the status of the rollout
undo Undo a previous rollout
Usage:
kubectl rollout SUBCOMMAND [options]
Use "kubectl rollout <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).
示例:
# 再次更新镜像为 docker.io/library/nginx:1.28
[root@master30 ~]# kubectl set image deployment/web nginx=docker.io/library/nginx:1.28 --record
# 查看更新记录
[root@master30 ~]# kubectl rollout history deployment web
deployment.apps/web
REVISION CHANGE-CAUSE
1 <none>
2 kubectl set image deployment/web nginx=docker.io/library/nginx:1.28 --record=true
3 kubectl set image deployment/web nginx=nginx:1.29 --record=true
# 回滚到版本1
[root@master30 ~]# kubectl rollout undo deployment web --to-revision=1
deployment.apps/web rolled back
[root@master30 ~]# kubectl rollout history deployment web
deployment.apps/web
REVISION CHANGE-CAUSE
2 kubectl set image deployment/web *=docker.io/library/nginx:1.28 --record=true
3 kubectl set image deployment/web *=nginx:1.29 --record=true
4 <none>
滚动更新
Kubernetes提供了两个参数maxSurge和maxUnavailable来精细控制Pod的替换数量 。
-
**maxSurge,此参数控制滚动更新过程中副本总数超过 DESIRED 的上限的数量。**maxSurge可以是具体的整数(比如3) , 也可以是百分百, 向上取整。 maxSurge默认值为25%。
例如, DESIRED为10, 那么副本总数的最大值为 roundUp(10 + 10 * 25%) =13, 所以我们看到 CURRENT 就是13。
-
maxUnavailable,此参数控制滚动更新过程中不可用的副本相占DESIRED的最大比例。 maxUnavailable可以是具体的整数(比如3), 也可以是百分百, 向下取整。 maxUnavailable默认值为25%。
例如, DESIRED为10, 那么可用的副本数至少要为10 - roundDown(10 * 25%)= 8, 所以我们看到AVAILABLE是8。
总结:
- maxSurge 值越大, 初始创建的新副本数量就越多。
- **maxUnavailable **值越大, 初始销毁的旧副本数量就越多,更新初期造成不可用副本数量越多。
理想情况下, 我们这个案例滚动更新的过程应该是这样的:
- 创建3个新副本,此时Running副本数为10,maxSurge副本总数达到13。
- 销毁2个旧副本,同时再创建2个新副本。此时Running副本数为8。如果之前创建的3个副本状态没有变更为Running,则ContainerCreating副本数为5,maxSurge副本总数仍为13。
- 当新副本状态变更为Running, 例如之前创建的5个新副本在同一时刻状态变为running。当然这是一种理想情况。
- 此时running状态副本为13个,那么此时可以一次性销毁5个旧副本,同时又可以一次性创建5个新副本,使running副本数回到8。
- 这个过程会持续进行, 直到所有的旧副本被新副本替换,滚动更新完成。
**实践:**更新deployment镜像,并使用以下脚本监控:
[root@master30 ~]# vim monitor_pod_numbers
#!/bin/bash
while true
do
echo '===================' >> output.log
kubectl get pods --no-headers |awk '{print $3}' |sort | uniq -c |sed -r 's/^ +//'>> output.log
sleep 0.5
done
日志内容类似:
===================
10 Running
===================
5 ContainerCreating
8 Running
2 Terminating
===================
5 ContainerCreating
8 Running
2 Terminating
===================
5 ContainerCreating
8 Running
===================
5 ContainerCreating
8 Running
===================
3 ContainerCreating
1 Pending
9 Running
4 Terminating
===================
5 ContainerCreating
8 Running
5 Terminating
===================
5 ContainerCreating
8 Running
5 Terminating
===================
5 ContainerCreating
8 Running
3 Terminating
===================
10 Running
4 Terminating
===================
10 Running
2 Terminating
===================
10 Running
===================
10 Running
===================
环境清理
[root@master30 ~]# kubectl delete ns controllers
更多推荐




所有评论(0)