2026-04-23

复习和预习

昨天课堂内容

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

课前复习

默写

今天课堂内容

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

具体要求如下:

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

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

这里我们不详细介绍ReplicationController

Deployment

学习参考:Deployment

Deployment 介绍

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

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

Deployment 用例

以下是 Deployments 的典型用例:

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

  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 节点,路径:

    /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 节点。修改方法同上。

更新镜像
# 设置 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 **值越大, 初始销毁的旧副本数量就越多,更新初期造成不可用副本数量越多。

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

  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镜像,并使用以下脚本监控:

[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
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐