06.Kubernetes Secret和Kubernetes Controllers

2026-04-23

复习和预习

昨天课堂内容

  1. Volume
  2. ConfigMap
  3. 部署一个自己网站。

课前复习

默写

今天课堂内容

  1. secrets
  2. rs
  3. 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应用。

具体要求如下:

  1. 使用mysql、php-fpm、nginx镜像和wordpress-4.9.4-zh_CN.zip文件部署blog应用。
  2. blog应用通过https访问。
  3. 密码和站点证书用secret存储。
  4. 站点 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

ReplicationController ,简称RC,功能与ReplicaSets类似。 ReplicaSet 是 RC 的升级版, 支持新的基于集合的标签选择算符

这里我们不详细介绍ReplicationController

Deployment

学习参考:Deployment

Deployment 介绍

Deployment,简称 deploy,为 PodReplicaSet 提供声明式的更新能力。

ReplicaSet 能确保运行指定数量的pod。Deployment能管理ReplicaSets,并提供对pod的更新等功能。因此,我们建议你使用Deployment来管理ReplicaSets,除非你需要自定义更新编排。这意味着你可能永远不需要操作ReplicaSet对象,而是使用Deployment替代管理 。

Deployment 用例

以下是 Deployments 的典型用例:

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 个阶段

  1. Node 节点上kubelet 默认 每 10s 发一次心跳上报自身状态(kubelet → kube-apiserver)

  2. Master 上 controller-manager5 秒检查一次心跳,连续 40s 没收到 Node节点心跳,判定 Node 节点不健康,b标记为 NotReady

    参数:node-monitor-period=5snode-monitor-grace-period=40s

    该参数属于 kube-controller-manager 组件,该组件以静态 Pod 形式运行在 master 节点,路径:

    bash 复制代码
    /etc/kubernetes/manifests/kube-controller-manager.yaml

    编辑静态 Pod 配置文件,找到 command 段,添加或修改 --pod-eviction-timeout 参数,保存文件,触发静态 Pod 重启。

  3. 节点 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 **值越大, 初始销毁的旧副本数量就越多,更新初期造成不可用副本数量越多。

理想情况下, 我们这个案例滚动更新的过程应该是这样的:

  1. 创建3个新副本,此时Running副本数为10,maxSurge副本总数达到13。
  2. 销毁2个旧副本,同时再创建2个新副本。此时Running副本数为8。如果之前创建的3个副本状态没有变更为Running,则ContainerCreating副本数为5,maxSurge副本总数仍为13。
  3. 当新副本状态变更为Running, 例如之前创建的5个新副本在同一时刻状态变为running。当然这是一种理想情况。
  4. 此时running状态副本为13个,那么此时可以一次性销毁5个旧副本,同时又可以一次性创建5个新副本,使running副本数回到8。
  5. 这个过程会持续进行, 直到所有的旧副本被新副本替换,滚动更新完成。

**实践:**更新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
相关推荐
雨奔2 小时前
Kubernetes 实操:创建 LimitRange 和 Pod 并管理内存资源
云原生·容器·kubernetes
LSL666_2 小时前
什么是微服务
微服务·云原生·架构
lars_lhuan3 小时前
K8s跨命名空间SSL认证解决方案:Reflector工具实战
容器·kubernetes·ssl
郝开3 小时前
Docker Compose 本地环境搭建:redis
redis·docker·容器
青槿吖4 小时前
第二篇:从复制粘贴到自定义规则!Spring Cloud Gateway 断言 + 过滤全玩法,拿捏微服务流量管控
java·spring boot·后端·spring cloud·微服务·云原生·架构
爱莉希雅&&&4 小时前
Ansible+Docker案例(含ansible配置安装docker)
linux·运维·mysql·nginx·docker·容器·ansible
lulukanshijie4 小时前
Helm 入门:Kubernetes 包管理器介绍
其他·云原生·容器·kubernetes
王的宝库5 小时前
【K8s】集群安全机制(三):准入控制
网络·安全·kubernetes
七七powerful5 小时前
Kubernetes 弹性伸缩(HPA)设计思想深度解析
云原生·容器·kubernetes