2026-04-23
复习和预习
昨天课堂内容
- Volume
- ConfigMap
- 部署一个自己网站。
课前复习
默写
今天课堂内容
- secrets
- rs
- deployment
Kubernetes Secret
环境准备
bash
[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
bash
# 帮助信息
[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
......
基于键值对
一般用于传递变量值。
bash
[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
基于普通文件
一般用于传递配置文件。
bash
[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
基于键值对内容的文件
bash
[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。
bash
[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 文件
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。
bash
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]
示例:
bash
[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 编码。
bash
Usage:
kubectl create secret tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run=server|client|none] [options]
创建私钥和证书
bash
#--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
bash
[root@master30 certs]# kubectl create secret tls www-tls --cert=./www.crt --key=./www.key
Secret 引用
Secrets可以以卷方式挂载给pods,也可以通过环境变量方式传递给pods。
以环境变量方式引用
示例:
bash
[root@master30 ~]# vim pod-secret-env.yaml
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
验证
bash
[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 方式引用
bash
[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
引用整体
示例:
bash
[root@master30 ~]# vim pod-secret-volume-all.yaml
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
验证
bash
[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
bash
[root@master30 ~]# vim pod-secret-volume-single.yaml
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
或者
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
# 将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
验证
bash
[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内容:
bash
[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。
yaml
volumes:
- name: foo
secret:
secretName: mysecret1
defaultMode: 256
10进制是256转换成8进制是400。因为json格式不支持8进制,所以使用10进制。
bash
[root@master30 ~]# kubectl exec mypod1 -- ls -l /etc/foo/..data/user
-r-------- 1 root root 4 Aug 9 08:58 /etc/foo/..data/user
设置映射的单独文件权限
yaml
volumes:
- name: foo
secret:
secretName: mysecret1
items:
- key: user
path: user
mode: 511
10进制是511转换成8进制是777。
bash
[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
bash
[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
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
bash
[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
创建私钥和证书
bash
#--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
bash
[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
准备虚拟主机配置文件
bash
[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
yaml
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 类)
yaml
1. pods # Pod
2. replicationcontrollers # RC (很少用)
3. services # Service
4. daemonsets # DaemonSet
5. deployments # Deployment
6. replicasets # ReplicaSet
7. statefulsets # StatefulSet
下面这些都不在 all 里,必须单独 get:
yaml
- configmaps (cm) ⚠️ 不在 all 里
- secrets (secret) ⚠️ 不在 all 里
- ingress (ing) ⚠️ 不在 all 里
- persistentvolumes (pv) ⚠️
- persistentvolumeclaims (pvc) ⚠️
- endpoints (ep) ⚠️
- events (ev) ⚠️
- jobs
- cronjobs
- roles / clusterroles
- serviceaccounts
- hpa
查看真正的 "所有资源"
bash
kubectl get all,cm,secret,pvc,ingress
环境清理
bash
[root@master30 ~]# kubectl delete ns secret
Kubernetes Controllers
学习参考:控制器
环境准备
bash
[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 创建
bash
[root@master30 ~]# vim rs.yaml
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
bash
[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:删除单个副本
bash
[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
bash
[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。
bash
[root@master30 ~]# kubectl delete rs nginx
[root@master30 ~]# kubectl get pods
使用**--cascade=orphan**选项,只删除RS,保留pod。
bash
[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 管理
创建
命令行方式
bash
[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 文件方式
bash
# 获取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
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是必需的。
bash
[root@master30 ~]# kubectl apply -f deployment-web.yaml
创建方式进行比较
- 基于命令行的方式:
- 简单、 直观、 快捷, 上手快。
- 适合临时测试或实验。
- 基于配置文件的方式:
- 配置文件描述了What, 即应用最终要达到的状态。
- 配置文件提供了创建资源的模板, 能够重复部署。
- 可以像管理代码一样管理部署。
- 适合正式的、 跨环境的、 规模化部署。
- 这种方式要求熟悉配置文件的语法, 有一定难度。
**kubectl apply **命令不但能够创建Kubernetes资源, 也能对资源进行更新, 非常方便。
编辑
bash
# 方法1:命令行直接修改
[root@master30 ~]# kubectl edit deployments.apps web
# 方法2:编辑资源文件,然后apply应用
# 方法3:命令行修改,例如修改deployment副本数
[root@master30 ~]# kubectl scale deployment web --replicas=4
删除
删除deployments时,默认会删除deployments管理的子资源。
bash
[root@master30 ~]# kubectl delete deployments.apps web
deployment.apps "web" deleted
使用**--cascade=orphan选项**删除deployments,不会删除deployments管理的子资源。
bash
[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
水平伸缩
bash
# 创建 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重建。
bash
[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 节点,路径:
bash/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 节点。修改方法同上。
更新镜像
bash
# 设置 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版本。
bash
[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).
示例:
bash
# 再次更新镜像为 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镜像,并使用以下脚本监控:
bash
[root@master30 ~]# vim monitor_pod_numbers
bash
#!/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
日志内容类似:
bash
===================
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
===================
环境清理
bash
[root@master30 ~]# kubectl delete ns controllers