第五周 -kubernetes(三)

本贴最后更新于 455 天前,其中的信息可能已经东海扬尘

一、实现基于 velero 对 etcd 的单独 namespace 的备份和恢复

Velero 简介

  • Velero 是 VMware 开源的云原生的灾难恢复和迁移工具,本身是开源的,采用 Go 语言编写,开源安全的备份、恢复和迁移 kubernetes 集群资源数据,https://velero.io/
  • Velero 支持标准的 k8s 集群,既可以是私有云平台,也可以是公有云平台,除了灾备之外还能做资源迁移,支持把容器应用从一个集群迁移到另一个集群。
  • Velero 的工作方式就是把 k8s 中数据备份到数据存储以实现高可用和持久化,默认备份保存时间为 720 小时,并在需要的时候进行下载和恢复。

Velero 与 etcd 快照备份区别

  • etcd 快照是全局备份,在即使一个资源对象需要恢复,也需要做全局恢复到备份状态,会影响其它 namespace 中 pod 运行服务。
  • Velero 可以针对性的备份,比如按照 namespace 单独备份、只备份单独的资源对象等,在恢复的时候只恢复单独 namespace 或资源对象,而不影响其它 namespace 中 pod 运行服务。
  • Velero 支持 ceph、oss 等对象存储,etcd 快照是本地文件。
  • Velero 支持任务计划实现周期备份,但 etcd 快照也可基于 cronjob 实现。

Velero 备份流程

  1. Velero 客户端调用 kubernetes API Server 创建 Backup 任务
  2. Backup 控制器基于 watch 机制通过 API Server 获取备份任务
  3. Backup 控制器开始执行备份动作,其会通过请求 API Server 获取需要备份的数据
  4. Backup 控制器将获取到的数据备份到指定的对象存储 server 端

准备存储环境

1. 部署 minio

位部署服务器(10.0.0.8)

  • 安装 docker

    安装方法见上一节 siyuan://blocks/20230117185040-38eg2ps

  • 部署 minio

    # 下载minio镜像,打tag,上传至本地harbor仓库
    docker pull minio/minio:RELEASE.2022-12-12T19-27-27Z
    docker tag minio/minio:RELEASE.2022-12-12T19-27-27Z harbor.chu.net/baseimages/minio:2022-12-12T19-27-27Z
    docker push harbor.chu.net/baseimages/minio:2022-12-12T19-27-27Z
    
    # 创建数据目录
    mkdir -p /data/minio
    
    # 创建minio容器,如果不指定,则默认用户名与密码为minioadmin/minioadmin,可通过环境自定义
    docker run --name minio \
    -p 9000:9000 \
    -p 9999:9999 \
    -d --restart=always \
    -e "MINIO_ROOT_USER=admin" \
    -e "MINIO_ROOT_PASSWORD=12345678" \
    -v /data/minio/data:/data \
    harbor.chu.net/baseimages/minio:2022-12-12T19-27-27Z server /data \
    --console-address '0.0.0.0:9999'
    

2. 创建 bucket

  • 登录 web 界面

用户名:admin,密码:12345678

image

  • 进入管理页面

image

  • 创建 bucket

image

  • 验证 bucket

image

部署 velero

位 master1 节点部署

1. 下载 velero

https://github.com/vmware-tanzu/velero/releases

# 下载并解压
cd /usr/local/src
#wget https://github.com/vmware-tanzu/velero/releases/download/v1.8.1/velero-v1.8.1-linux-amd64.tar.gz
#tar xvf velero-v1.8.1-linux-amd64.tar.gz
wget https://github.com/vmware-tanzu/velero/releases/download/v1.9.4/velero-v1.9.4-linux-amd64.tar.gz
tar xvf velero-v1.9.4-linux-amd64.tar.gz
cp velero-v1.9.4-linux-amd64/velero  /usr/local/bin/

查看 velero 说明

[root@k8s-master1 src]#velero  -h
Velero is a tool for managing disaster recovery, specifically for Kubernetes
cluster resources. It provides a simple, configurable, and operationally robust
way to back up your application state and associated data.

If you're familiar with kubectl, Velero supports a similar model, allowing you to
execute commands such as 'velero get backup' and 'velero create schedule'. The same
operations can also be performed as 'velero backup get' and 'velero schedule create'.

Usage:
  velero [command]

Available Commands:
  backup            Work with backups
  backup-location   Work with backup storage locations
  bug               Report a Velero bug
  client            Velero client related commands
  completion        Generate completion script
  create            Create velero resources
  debug             Generate debug bundle
  delete            Delete velero resources
  describe          Describe velero resources
  get               Get velero resources
  help              Help about any command
  install           Install Velero
  plugin            Work with plugins
  restic            Work with restic
  restore           Work with restores
  schedule          Work with schedules
  snapshot-location Work with snapshot locations
  uninstall         Uninstall Velero
  version           Print the velero version and associated image

Flags:
      --add_dir_header                   If true, adds the file directory to the header
      --alsologtostderr                  log to standard error as well as files
      --colorized optionalBool           Show colored output in TTY. Overrides 'colorized' value from $HOME/.config/velero/config.json if present. Enabled by default
      --features stringArray             Comma-separated list of features to enable for this Velero process. Combines with values from $HOME/.config/velero/config.json if present
  -h, --help                             help for velero
      --kubeconfig string                Path to the kubeconfig file to use to talk to the Kubernetes apiserver. If unset, try the environment variable KUBECONFIG, as well as in-cluster configuration
      --kubecontext string               The context to use to talk to the Kubernetes apiserver. If unset defaults to whatever your current-context is (kubectl config current-context)
      --log_backtrace_at traceLocation   when logging hits line file:N, emit a stack trace (default :0)
      --log_dir string                   If non-empty, write log files in this directory
      --log_file string                  If non-empty, use this log file
      --log_file_max_size uint           Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
      --logtostderr                      log to standard error instead of files (default true)
  -n, --namespace string                 The namespace in which Velero should operate (default "velero")
      --skip_headers                     If true, avoid header prefixes in the log messages
      --skip_log_headers                 If true, avoid headers when opening log files
      --stderrthreshold severity         logs at or above this threshold go to stderr (default 2)
  -v, --v Level                          number for the log level verbosity
      --vmodule moduleSpec               comma-separated list of pattern=N settings for file-filtered logging

Use "velero [command] --help" for more information about a command.

2. 准备 velero 认证环境

# 创建工作目录
mkdir -p /data/velero
cd /data/velero

# 访问minio的认证文件,minio用户名与配置
cat >> velero-auth.txt <<EOF
[default]
aws_access_key_id = admin
aws_secret_access_key = 12345678
EOF

# 准备user-csr文件,用于访问k8s;也可直接使用/root/.kube/config文件
cat >>awsuser-csr.json <<EOF
{
  "CN": "awsuser",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

# 准备证书签发环境
## 1. 从部署服务器复制
scp 10.0.0.8:/etc/kubeasz/bin/cfssl* /usr/local/bin/
## 2. 或者自行下载
apt install -y golang-cfssl
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl-certinfo_1.6.1_linux_amd64
mv cfssl-certinfo_1.6.1_linux_amd64 cfssl-certinfo
mv cfssl_1.6.1_linux_amd64 cfssl
mv cfssljson_1.6.1_linux_amd64 cfssljson
cp cfssl-certinfo cfssl cfssljson /usr/local/bin/
chmod  a+x /usr/local/bin/cfssl*

查看 cfssl 说明

[root@k8s-master1 velero]#cfssl -h
Usage:
Available commands:
	bundle
	certinfo
	serve
	ocspserve
	crl
	version
	gencert
	selfsign
	sign
	genkey
	scan
	print-defaults
	revoke
	gencsr
	gencrl
	ocspdump
	ocsprefresh
	ocspsign
	info
Top-level flags:
  -alsologtostderr
    	log to standard error as well as files
  -log_backtrace_at value
    	when logging hits line file:N, emit a stack trace
  -log_dir string
    	If non-empty, write log files in this directory
  -logtostderr
    	log to standard error instead of files
  -stderrthreshold value
    	logs at or above this threshold go to stderr
  -v value
    	log level for V logs
  -vmodule value
    	comma-separated list of pattern=N settings for file-filtered logging

3. 签发证书

cd /data/velero
# 从部署服务器复制ca-config.json文件
scp 10.0.0.8:/etc/kubeasz/clusters/k8s-cluster1/ssl/ca-config.json /data/velero/ca-config.json

# 执行证书签发
/usr/local/bin/cfssl gencert \
-ca=/etc/kubernetes/ssl/ca.pem \
-ca-key=/etc/kubernetes/ssl/ca-key.pem \
-config=./ca-config.json \
-profile=kubernetes \
./awsuser-csr.json | cfssljson -bare awsuser

验证证书

[root@k8s-master1 velero]#ls
awsuser-csr.json  awsuser-key.pem  awsuser.csr  awsuser.pem  ca-config.json  velero-auth.txt

4. 配置客户端认证

#分发证书到api-server证书路径
cp awsuser-key.pem /etc/kubernetes/ssl/
cp awsuser.pem /etc/kubernetes/ssl/

#生成集群认证config文件
export KUBE_APISERVER="https://10.0.0.10:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=./awsuser.kubeconfig


#设置客户端证书认证
kubectl config set-credentials awsuser \
--client-certificate=/etc/kubernetes/ssl/awsuser.pem \
--client-key=/etc/kubernetes/ssl/awsuser-key.pem \
--embed-certs=true \
--kubeconfig=./awsuser.kubeconfig

#设置上下文参数
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=awsuser \
--namespace=velero-system \
--kubeconfig=./awsuser.kubeconfig

#设置默认上下文
kubectl config use-context kubernetes --kubeconfig=awsuser.kubeconfig

查看 awsuser.kubeconfig​文件

[root@k8s-master1 velero]#cat awsuser.kubeconfig 
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTVRRek9EQXdXaGdQTNW1M...SXdRRERU5EIENFUlRJRklDQVRFLS0tLS0K
    server: https://10.0.0.10:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    namespace: velero-system
    user: awsuser
  name: kubernetes
current-context: kubernetes
kind: Config
preferences: {}
users:
- name: awsuser
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0...tLS0tCk1JSUS0tLS0tCg==
    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSh5...FdkMkNSCm5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

5. 创建用户

#k8s集群中创建awsuser账户
kubectl create clusterrolebinding awsuser --clusterrole=cluster-admin --user=awsuser

#创建namespace
kubectl create ns velero-system

6. 安装 velero

# 执行安装
velero --kubeconfig  ./awsuser.kubeconfig \	#连接k8s认证文件
install \					#安装
--provider aws \				#连接k8s用户
--plugins velero/velero-plugin-for-aws:v1.3.1 \	#velero镜像
--bucket velerodata  \				#minio bucket名称
--secret-file ./velero-auth.txt \		#连接minio认证文件
--use-volume-snapshots=false \			#是否使用快照
--namespace velero-system \			#namespace名称
--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://10.0.0.8:9000	#minio地址

velero --kubeconfig  ./awsuser.kubeconfig \
install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.3.1 \
--bucket velerodata  \
--secret-file ./velero-auth.txt \
--use-volume-snapshots=false \
--namespace velero-system \
--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://10.0.0.8:9000

验证

#验证安装
## 查看pod状态
[root@k8s-master1 velero]#kubectl get pod -n velero-system 
NAME                      READY   STATUS    RESTARTS   AGE
velero-58d44fc999-gc9dd   0/1     Pending   0          61s

## 查看pod安装状态
[root@k8s-master1 velero]#kubectl describe pod velero-58d44fc999-gc9dd -n velero-system
...
Events:
  Type     Reason            Age    From               Message
  ----     ------            ----   ----               -------
  Warning  FailedScheduling  4m13s  default-scheduler  0/6 nodes are available: 6 node(s) had untolerated taint {node.kubernetes.io/unschedulable: }, 6 node(s) were unschedulable. preemption: 0/6 nodes are available: 6 Preemption is not helpful for scheduling.
  Normal   Scheduled         70s    default-scheduler  Successfully assigned velero-system/velero-58d44fc999-gc9dd to 10.0.0.41
  Normal   Pulling           69s    kubelet            Pulling image "velero/velero-plugin-for-aws:v1.3.1"
  Normal   Pulled            55s    kubelet            Successfully pulled image "velero/velero-plugin-for-aws:v1.3.1" in 14.121223331s
  Normal   Created           55s    kubelet            Created container velero-velero-plugin-for-aws
  Normal   Started           55s    kubelet            Started container velero-velero-plugin-for-aws
  Normal   Pulling           54s    kubelet            Pulling image "velero/velero:v1.9.4"

[root@k8s-master1 velero]#kubectl get pod -n velero-system 
NAME                      READY   STATUS    RESTARTS   AGE
velero-58d44fc999-gc9dd   1/1     Running   0          6m22s

## 查看logs确认正常启动,状态为valid
[root@k8s-master1 velero]#kubectl logs velero-58d44fc999-gc9dd -n velero-system
...
level=info msg="BackupStorageLocations is valid, marking as available" backup-storage-location=velero-system/default controller=backup-storage-location logSource="pkg/controller/backup_storage_location_controller.go:116"

备份

# 按当前日前对myserver namespace进行备份
DATE=`date +%Y%m%d%H%M%S`

velero backup create myserver-ns-backup-${DATE} \
--include-namespaces myserver \
--kubeconfig=/data/velero/awsuser.kubeconfig \
--namespace velero-system

查看备份

image

备份指定资源对象

#备份指定namespace中pod或特定资源
velero backup create pod-backup-01 \
--include-cluster-resources=true \
--ordered-resources 'pods=myserver/net-test1,default/net-test1' \
--namespace velero-system \
--include-namespaces=myserver,default

批量备份所有 namespace

#!/bin/bash
DATE=`date +%Y%m%d%H%M%S`
NS_NAME=`kubectl get ns|awk 'NR>1{print $1}'`
for NAME in ${NS_NAME};do
	velero backup create ${NAME}-ns-backup-${DATE} \
--include-namespaces ${NAME} \
--kubeconfig=/data/velero/awsuser.kubeconfig \
--namespace velero-system
done

恢复

  • 删除数据
[root@k8s-master1 velero]#kubectl delete pod net-test1 -n myserver 
pod "net-test1" deleted

[root@k8s-master1 velero]#kubectl delete pod net-test4 -n myserver 
pod "net-test4" deleted

[root@k8s-master1 velero]#kubectl delete pod net-test5 -n myserver 
pod "net-test5" deleted

[root@k8s-master1 velero]#kubectl get pod -n myserver 
NAME        READY   STATUS    RESTARTS       AGE
net-test2   1/1     Running   7 (111m ago)   5d3h
net-test3   1/1     Running   8 (111m ago)   5d3h
net-test6   1/1     Running   7 (111m ago)   5d3h
net-test7   1/1     Running   7 (111m ago)   5d3h
net-test8   1/1     Running   8 (111m ago)   5d3h
  • 执行恢复
velero restore create --from-backup myserver-ns-backup-20230125003851 --wait \
--kubeconfig=/data/velero/awsuser.kubeconfig \
--namespace velero-system
  • 验证恢复
# pod恢复正常
[root@k8s-master1 velero]#kubectl get pod -n myserver 
NAME        READY   STATUS    RESTARTS       AGE
net-test1   1/1     Running   0              20s
net-test2   1/1     Running   7 (112m ago)   5d3h
net-test3   1/1     Running   8 (113m ago)   5d3h
net-test4   1/1     Running   0              20s
net-test5   1/1     Running   0              20s
net-test6   1/1     Running   7 (112m ago)   5d3h
net-test7   1/1     Running   7 (112m ago)   5d3h
net-test8   1/1     Running   8 (113m ago)   5d3h

# 网络测试正常
[root@k8s-master1 velero]#kubectl exec -it net-test4 -n myserver sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # ping www.baidu.com
PING www.baidu.com (183.232.231.172): 56 data bytes
64 bytes from 183.232.231.172: seq=0 ttl=127 time=82.630 ms
64 bytes from 183.232.231.172: seq=1 ttl=127 time=67.564 ms

二、掌握 k8s 中常见的资源对象的使用

k8s 常用资源对象有 deployment、service、configmap、secret

Deployment

https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/deployment/

https://cloud.google.com/kubernetes-engine/docs/concepts/deployment?hl=zh-cn

​Deployment 指不具有唯一标识的一组多个相同的 Pod。Deployment 运行应用的多个副本,并自动替换任何失败或无响应的实例。通过这种方式,Deployment 可帮助确保应用的一个或多个实例可用于处理用户请求。Deployment 由 Kubernetes Deployment 控制器管理。

​Deployment 使用 Pod 模板,此模板包含适用于其 Pod 的规范。Pod 规范确定每个 Pod 的外观:应在其容器内运行的应用、Pod 应装载的卷及其标签等。

Deployment 的 Pod 模板更改时,系统会自动创建新 Pod,每次创建一个。

1. 应用场景

Deployment 非常适合使用在多个副本上挂载的 ReadOnlyMany 或 ReadWriteMany 卷的无状态应用,但不适合使用 ReadWriteOnce 卷的工作负载。如果是使用 ReadWriteOnce 卷的有状态应用,请使用 StatefulSet。StatefulSet 旨在用于部署有状态应用和将数据保存到永久性存储空间(例如 Compute Engine 永久性磁盘)的聚簇应用。StatefulSet 适合部署 Kafka、MySQL、Redis、ZooKeeper 以及其他需要唯一持久身份和稳定主机名的应用。

Deployment 典型的应用场景包括:

  • 创建 Deployment 以 ReplicaSet 上线。ReplicaSet 在后台创建 Pod。 检查 ReplicaSet 的上线状态,查看其是否成功。
  • 通过更新 Deployment 的 Pod 模板规范,声明 Pod 新状态 。 新的 ReplicaSet 会被创建,Deployment 以受控速率将 Pod 从旧 ReplicaSet 迁移到新 ReplicaSet。 每个新的 ReplicaSet 都会更新 Deployment 的修订版本。
  • 如果 Deployment 的当前状态不稳定,回滚到较早的 Deployment 版本。 每次回滚都会更新 Deployment 的修订版本。
  • 扩大 Deployment 规模以承担更多负载。
  • 暂停 Deployment 的上线 以应用对 PodTemplateSpec 所作的多项修改, 然后恢复其执行以启动新的上线版本。
  • 使用 Deployment 状态来判定上线过程是否出现停滞。
  • 清理较旧的不再需要的 ReplicaSet 。

2. 创建 deployment

2.1 编写 yaml 文件

创建了一个 ReplicaSet,负责启动三个 nginx​ Pod,文件名为 nginx-deployment.yaml

apiVersion: apps/v1		# 注意这里与Pod的区别,Deployment是apps/v1而不是v1,可通过kubectl explain deployment查看
kind: Deployment		# 资源类型为Deployment
metadata:			# deployment元数据
  name: nginx-deployment	# Deployment名称
  labels:			# deployment标签
    app: nginx			# 定义deployment标签为app:nginx
spec:
  replicas: 3			# Pod的数量,Deployment会确保一直有3个Pod运行
  selector:			# Label Selector
    matchLabels:		# 匹配pod标签
      app: nginx		# 匹配pod的标签内容为app:nginx
  template:			# Pod的定义,用于创建Pod,也称为Pod template
    metadata:			# pod元数据
      labels:			# pod标签
        app: nginx		# 定义pod标签内容为app:nginx
    spec:			# 容器的定义,用于创建容器
      containers:
      - name: nginx		# 容器的名称
        image: nginx:1.14.2	# 容器使用的镜像
        ports:			# 设置暴露端口
        - containerPort: 80	# 容器端口80
        resources:		# 定义容器的使用资源
          limits:		# 限制
            cpu: 200m		# cpu最多使用200毫颗(0.2颗)
            memory: 300Mi	# 内存最多使用300Mi
          requests:		# 最少需要
            cpu: 100m		# cpu至少需要100毫颗(0.1颗)
            memory: 200Mi	# 内存至少需要200Mi

说明

  • 创建名为 nginx-deployment​​(由 .metadata.name​​ 字段标明)的 Deployment。 该名称将成为后续创建 ReplicaSet 和 Pod 的命名基础。 参阅编写 Deployment 规约获取更多详细信息。

  • 该 Deployment 创建一个 ReplicaSet,它创建三个(由 .spec.replicas​​ 字段标明)Pod 副本。

  • .spec.selector​​ 字段定义所创建的 ReplicaSet 如何查找要管理的 Pod。选择在 Pod 模板中定义的标签(app: nginx​​)。 不过,更复杂的选择规则是也可能的,只要 Pod 模板本身满足所给规则即可。

    **注意:**​spec.selector.matchLabels​ 字段是 {key,value}​ 键值对映射。 在 matchLabels​ 映射中的每个 {key,value}​ 映射等效于 matchExpressions​ 中的一个元素, 即其 key​ 字段是 “key”,operator​ 为 “In”,values​ 数组仅包含 “value”。 在 matchLabels​ 和 matchExpressions​ 中给出的所有条件都必须满足才能匹配。

  • template​ 字段包含以下子字段:

    • Pod 被使用 .metadata.labels​ 字段打上 app: nginx​ 标签。
    • Pod 模板规约(即 .template.spec​ 字段)指示 Pod 运行一个 nginx​ 容器, 该容器运行版本为 1.14.2 的 nginxDocker Hub 镜像。
    • 创建一个容器并使用 .spec.template.spec.containers[0].name​ 字段将其命名为 nginx​。
    • 打开端口 80 以供 Pod 使用。

2.2 创建 deployment

kubectl apply -f nginx-deployment.yaml

2.3 查看运行状态

查看 deployment 运行状态

[root@k8s-deploy yaml]#kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           41s

在检查集群中的 Deployment 时,所显示的字段有:

  • NAME​ 列出了名字空间中 Deployment 的名称。
  • READY​ 显示应用程序的可用的“副本”数。显示的模式是“就绪个数/期望个数”。
  • UP-TO-DATE​ 显示为了达到期望状态已经更新的副本数。
  • AVAILABLE​ 显示应用可供用户使用的副本数。
  • AGE​ 显示应用程序运行的时间。

**注意:**期望副本数是根据 .spec.replicas​ 字段设置。

当前显示 Deployment 已创建全部三个副本,并且所有副本都是最新的(它们包含最新的 Pod 模板) 并且可用。

2.4 查看上线状态

查看 Deployment 上线状态

[root@k8s-deploy yaml]#kubectl describe deploy nginx-deployment
Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Wed, 25 Jan 2023 13:49:39 +0800
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=nginx
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:      nginx:1.14.2
    Port:       80/TCP
    Host Port:  0/TCP
    Limits:
      cpu:     200m
      memory:  300Mi
    Requests:
      cpu:        100m
      memory:     200Mi
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-deployment-6559b4d948 (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  96s   deployment-controller  Scaled up replica set nginx-deployment-6559b4d948 to 3

2.5 查看 ReplicaSet(​rs​)

查看 Deployment 创建的 ReplicaSet(rs)

[root@k8s-deploy yaml]#kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-6559b4d948   3         3         3       2m15s

ReplicaSet 输出中包含以下字段:

  • NAME​ 列出名字空间中 ReplicaSet 的名称;
  • DESIRED​ 显示应用的期望副本个数,即在创建 Deployment 时所定义的值。 此为期望状态;
  • CURRENT​ 显示当前运行状态中的副本个数;
  • READY​ 显示应用中有多少副本可以为用户提供服务;
  • AGE​ 显示应用已经运行的时间长度。

**注意:**ReplicaSet 的名称格式始终为 [Deployment 名称]-[哈希]​。 该名称将成为所创建的 Pod 的命名基础(pod 命名为:ReplicaSet ​ [name]​+pod [哈希]​)。 其中哈希字符串与 ReplicaSet 上的 pod-template-hash​ 标签一致。

2.6 查看 Pod 标签

查看每个 Pod 自动生成的标签

[root@k8s-deploy yaml]#kubectl get pod --show-labels
NAME                                READY   STATUS    RESTARTS   AGE     LABELS
nginx-deployment-6559b4d948-l4nsj   1/1     Running   0          3m24s   app=nginx,pod-template-hash=6559b4d948
nginx-deployment-6559b4d948-p7v6l   1/1     Running   0          3m24s   app=nginx,pod-template-hash=6559b4d948
nginx-deployment-6559b4d948-vq5k8   1/1     Running   0          3m24s   app=nginx,pod-template-hash=6559b4d948

**注意:**必须在 Deployment 中指定适当的选择算符和 Pod 模板标签(在本例中为 app: nginx​)。 标签或者选择算符不要与其他控制器(包括其他 Deployment 和 StatefulSet)重叠。 Kubernetes 不会阻止你这样做,但是如果多个控制器具有重叠的选择算符, 它们可能会发生冲突执行难以预料的操作。

2.7 Pod-template-hash 标签

Deployment 控制器将 pod-template-hash​ 标签添加到 Deployment 所创建或收留的每个 ReplicaSet 。

此标签可确保 Deployment 的子 ReplicaSets 不重叠。 标签是通过对 ReplicaSet 的 PodTemplate​ 进行哈希处理。 所生成的哈希值被添加到 ReplicaSet 选择算符、Pod 模板标签,并存在于在 ReplicaSet 可能拥有的任何现有 Pod 中。

3. 更新 deployment

  • 仅当 Deployment Pod 模板(即 .spec.template​​​)发生改变时,例如模板的标签或容器镜像被更新, 才会触发 Deployment 上线。其他更新(如对 Deployment 执行扩缩容的操作)不会触发上线动作。
  • 通过更改 Deployment 的 Pod 模板规范来更新 Deployment。更改规范字段会自动触发更新发布。可以使用 kubectl​​​、Kubernetes API。
  • 默认情况下,当 Deployment 触发更新时,Deployment 会停止 Pod,逐渐将 Pod 数量减少到零,然后排出并终止 Pod。然后,Deployment 使用经过更新的 Pod 模板来产生新的 Pod。
  • 只有正在运行的新 Pod 达到足够数量时,才会删除旧 Pod,同时只有删除的旧 Pod 达到足够数量时,才会创建新 Pod。如需查看 Pod 生成和移除的顺序,可运行 kubectl describe deployments​​​​查看。
  • Deployment 可以确保正在运行的副本数量至少比所需数量少一个,同时最多只有一个 Pod 不可用。同样,Deployment 可以确保正在运行的副本数量最多比所需数量多一个,正在运行的 Pod 数量最多比所需数量多一个。

3.1 更新

如需将 nginx Pod 镜像从 nginx:1.14.2​升级至 nginx:1.16.1​ ,更新 deployment 方式有:

  • 命令方式更新
kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
# 或者kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1

或者执行 edit​ 操作并将 .spec.template.spec.containers[0].image​ 从 nginx:1.14.2​ 更改至 nginx:1.16.1​。

kubectl edit deployment/nginx-deployment

  • 修改 yaml 文件更新

将原 yaml 文件中 .spec.template.spec.containers[0].image​ 从 nginx:1.14.2​ 更改至 nginx:1.16.1​。

# 修改完成后,执行如下命令
kubectl apply -f nginx-deployment.yaml

更新过程状态如下:

# 查看上线状态
[root@k8s-deploy yaml]#kubectl rollout status deploy/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...

# 更新过程,先创建新pod,原pod保留,待一个新pod正常运行后,删除一个旧pod
[root@k8s-deploy yaml]#kubectl get pod
NAME                                READY   STATUS              RESTARTS   AGE
nginx-deployment-78fb746c6d-c8mc4   1/1     Running             0          10m
nginx-deployment-79cd9bd469-27pvc   0/1     ContainerCreating   0          84s
nginx-deployment-79cd9bd469-78l9g   1/1     Running             0          3m46s
nginx-deployment-79cd9bd469-wspvh   1/1     Running             0          2m41s

# 更新完成,保留3个新的pod,旧pod删除
[root@k8s-deploy yaml]#kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-79cd9bd469-27pvc   1/1     Running   0          96s
nginx-deployment-79cd9bd469-78l9g   1/1     Running   0          3m58s
nginx-deployment-79cd9bd469-wspvh   1/1     Running   0          2m53s

3.2 查看状态

# 查看deployment
[root@k8s-deploy yaml]#kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           12m

# 查看rs
[root@k8s-deploy yaml]#kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-78fb746c6d   0         0         0       12m
nginx-deployment-79cd9bd469   3         3         3       4m33s

# 查看pod
[root@k8s-deploy yaml]#kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-79cd9bd469-27pvc   1/1     Running   0          96s
nginx-deployment-79cd9bd469-78l9g   1/1     Running   0          3m58s
nginx-deployment-79cd9bd469-wspvh   1/1     Running   0          2m53s

4. 回滚 deployment

当 Deployment 不稳定时(例如进入反复崩溃状态),需要回滚 Deployment;默认情况下,系统保留 10 次 Deployment 的 revision,以便可以随时回滚 (可以修改 revision history limit​ 来更改保存的历史记录数)。

**说明:**Deployment 被触发上线时,系统就会创建 Deployment 的新的 revision。这意味着仅当 Deployment 的 Pod 模板(.spec.template​)发生更改时,才会创建新 revision:例如,模板的标签或容器镜像发生变化。其他更新,如 Deployment 的扩缩容操作不会创建 Deployment revision。 这是为了方便同时执行手动缩放或自动缩放。这意味着当回退到历史 revision 时,只有 Deployment 中的 Pod 模板部分才会回退。

查看 Deployment 历史版本

假设在更新 Deployment 时犯了一个拼写错误,将镜像名称命名设置为 nginx:1.161​ 而不是 nginx:1.16.1​:

kubectl set image deployment/nginx-deployment nginx=nginx:1.161
  1. 检查 Deployment 修订历史
[root@k8s-deploy yaml]#kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
4         <none>
5         <none>
6         <none>
  1. 要查看指定历史版本的详细信息
[root@k8s-deploy yaml]#kubectl rollout history deployment/nginx-deployment --revision=5
deployment.apps/nginx-deployment with revision #5
Pod Template:
  Labels:	app=nginx
	pod-template-hash=79cd9bd469
  Containers:
   nginx:
    Image:	nginx:1.16.1
    Port:	80/TCP
    Host Port:	0/TCP
    Limits:
      cpu:	200m
      memory:	300Mi
    Requests:
      cpu:	100m
      memory:	200Mi
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>

回滚到之前的版本

  1. 回滚到历史版本
  • 回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment
  • 回滚到指定版本

使用 --to-revision​ 回滚到指定版本(如版本 5)

kubectl rollout undo deployment/nginx-deployment --to-revision=5

  1. 检查回滚是否成功以及 Deployment 是否正在运行
[root@k8s-deploy yaml]#kubectl get deployment nginx-deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           7h56m
  1. 查看 Deployment 描述信息:
[root@k8s-deploy yaml]#kubectl describe deployment nginx-deployment
...
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  51m    deployment-controller  Scaled up replica set nginx-deployment-59c554777d to 1
  Normal  ScalingReplicaSet  48m    deployment-controller  Scaled down replica set nginx-deployment-59c554777d to 0
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled up replica set nginx-deployment-f75dc4657 to 1
  Normal  ScalingReplicaSet  9m35s  deployment-controller  Scaled down replica set nginx-deployment-f75dc4657 to 0

5. 缩放 deployment

执行缩放命令

# 将nginx-deployment副本扩展至6个
kubectl scale deployment/nginx-deployment --replicas=6

验证

# 查看deploy
[root@k8s-deploy yaml]#kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   6/6     6            6           8h

# 查看rs
[root@k8s-deploy yaml]#kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-59c554777d   0         0         0       60m
nginx-deployment-6559b4d948   0         0         0       8h
nginx-deployment-78fb746c6d   0         0         0       83m
nginx-deployment-79cd9bd469   6         6         6       75m
nginx-deployment-f75dc4657    0         0         0       26m

# 查看pod
[root@k8s-deploy yaml]#kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-79cd9bd469-27pvc   1/1     Running   0          73m
nginx-deployment-79cd9bd469-56dsx   1/1     Running   0          6m30s
nginx-deployment-79cd9bd469-78l9g   1/1     Running   0          75m
nginx-deployment-79cd9bd469-jhbs4   1/1     Running   0          6m30s
nginx-deployment-79cd9bd469-qmz68   1/1     Running   0          6m30s
nginx-deployment-79cd9bd469-wspvh   1/1     Running   0          74m

6. 暂停和恢复 deployment

在触发一次或多次更新前暂停一个 Deployment,然后再恢复它。这样就能在 Deployment 暂停期间进行多次修复工作,而不会发出不必要的 rollout。

以 nginx-deployment 为例:

  1. 获取 deployment 信息
[root@k8s-deploy yaml]#kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   6/6     6            6           8h

[root@k8s-deploy yaml]#kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-59c554777d   0         0         0       72m
nginx-deployment-6559b4d948   0         0         0       8h
nginx-deployment-78fb746c6d   0         0         0       95m
nginx-deployment-79cd9bd469   6         6         6       87m
nginx-deployment-f75dc4657    0         0         0       38m
  1. 暂停 deployment 上线
kubectl rollout pause deploy/nginx-deployment
  1. 查看历史更新记录
[root@k8s-deploy yaml]#kubectl rollout history deploy/nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         <none>
4         <none>
6         <none>
7         <none>
8         <none>
  1. 更新 deployment 镜像
kubectl set image deploy/nginx-deployment nginx=nginx:1.16.0
  1. 查看历史更新记录

没有新的上线被触发

[root@k8s-deploy yaml]#kubectl rollout history deploy/nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         <none>
4         <none>
6         <none>
7         <none>
8         <none>
  1. 获取上线状态验证现有的 ReplicaSet 没有被更改
[root@k8s-deploy yaml]#kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-59c554777d   0         0         0       82m
nginx-deployment-6559b4d948   0         0         0       8h
nginx-deployment-78fb746c6d   0         0         0       105m
nginx-deployment-79cd9bd469   6         6         6       97m
nginx-deployment-f75dc4657    0         0         0       48m

暂停 Deployment 上线之前的初始状态将继续发挥作用,根据需要可执行很多更新操作,但新的更新在 Deployment 上线被暂停期间不会产生任何效果。

  1. 恢复 deployment 上线
kubectl rollout resume deploy/nginx-deployment
  1. 查看上线过程
[root@k8s-deploy yaml]#kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   5/6     3            5           8h

[root@k8s-deploy yaml]#kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-59c554777d   0         0         0       87m
nginx-deployment-6559b4d948   0         0         0       8h
nginx-deployment-78fb746c6d   0         0         0       109m
nginx-deployment-79cd9bd469   5         5         5       102m
nginx-deployment-9dd69d6c8    3         3         0       89s
nginx-deployment-f75dc4657    0         0         0       52m

[root@k8s-deploy yaml]#kubectl get pod
NAME                                READY   STATUS              RESTARTS   AGE
nginx-deployment-79cd9bd469-27pvc   1/1     Running             0          100m
nginx-deployment-79cd9bd469-56dsx   1/1     Running             0          32m
nginx-deployment-79cd9bd469-78l9g   1/1     Running             0          102m
nginx-deployment-79cd9bd469-jhbs4   1/1     Running             0          32m
nginx-deployment-79cd9bd469-wspvh   1/1     Running             0          101m
nginx-deployment-9dd69d6c8-cm9nl    0/1     ContainerCreating   0          100s
nginx-deployment-9dd69d6c8-vlw8d    0/1     ContainerCreating   0          100s
nginx-deployment-9dd69d6c8-vp9t8    0/1     ContainerCreating   0          100s
  1. 查看完成状态
[root@k8s-deploy yaml]#kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-59c554777d   0         0         0       92m
nginx-deployment-6559b4d948   0         0         0       8h
nginx-deployment-78fb746c6d   0         0         0       114m
nginx-deployment-79cd9bd469   0         0         0       107m
nginx-deployment-9dd69d6c8    6         6         6       6m25s
nginx-deployment-f75dc4657    0         0         0       57m

[root@k8s-deploy yaml]#kubectl get pod
NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-9dd69d6c8-2dfwz   1/1     Running   0          4m21s
nginx-deployment-9dd69d6c8-4tvr5   1/1     Running   0          4m20s
nginx-deployment-9dd69d6c8-77hff   1/1     Running   0          4m24s
nginx-deployment-9dd69d6c8-cm9nl   1/1     Running   0          6m54s
nginx-deployment-9dd69d6c8-vlw8d   1/1     Running   0          6m54s
nginx-deployment-9dd69d6c8-vp9t8   1/1     Running   0          6m54s

**注意:**不可以回滚处于暂停状态的 Deployment,除非先恢复其执行状态。

7. deployment 状态

Deployment 在其生命周期中可以处于以下三种状态:Progressing(进行中),Complete(已完成),Failed(失败)。

Progressing

执行下面的任务期间,Kubernetes 标记 Deployment 为 Progressing:

  • Deployment 创建新的 ReplicaSet
  • Deployment 正在为其最新的 ReplicaSet 扩容
  • Deployment 正在为其旧有的 ReplicaSet(s) 缩容
  • 新的 Pod 已经就绪或者可用(就绪至少持续了 MinReadySeconds 秒)。

当上线过程进入“Progressing”状态时,Deployment 控制器会向 Deployment 的 .status.conditions​ 中添加包含下面属性的状况条目:

  • type: Progressing
  • status: "True"
  • reason: NewReplicaSetCreated​ | reason: FoundNewReplicaSet​ | reason: ReplicaSetUpdated

可执行 kubectl rollout status​ 监视 Deployment 的进度。

Complete

当 Deployment 具有以下特征时,Kubernetes 将其标记为 Complete

  • 与 Deployment 关联的所有副本都已更新到指定的最新版本,这意味着之前请求的所有更新都已完成。
  • 与 Deployment 关联的所有副本都可用。
  • 未运行 Deployment 的旧副本。

当上线过程进入“Complete”状态时,Deployment 控制器会向 Deployment 的 .status.conditions​ 中添加包含下面属性的状况条目:

  • type: Progressing
  • status: "True"
  • reason: NewReplicaSetAvailable

Progressing​ 状态值会持续为 "True"​,直至新的上线动作被触发。 即使副本的可用状态发生变化(进而影响 Available​ 状况),Progressing​ 状况的值也不会变化。

可以使用 kubectl rollout status​ 检查 Deployment 是否已完成。 如果上线成功完成,kubectl rollout status​ 输出 successfully rolled out​。

Failed

Deployment 可能会在尝试部署其最新的 ReplicaSet 受挫,一直处于未完成状态。 造成此情况一些可能因素如下:

  • 配额(Quota)不足
  • 就绪探测(Readiness Probe)失败
  • 镜像拉取错误
  • 权限不足
  • 限制范围(Limit Ranges)问题
  • 应用程序运行时的配置错误

超过截止时间后,Deployment 控制器将添加具有以下属性的 Deployment 状况到 Deployment 的 .status.conditions​ 中:

  • type: Progressing
  • status: "False"
  • reason: ProgressDeadlineExceeded

这一状况也可能会比较早地失败,因而其状态值被设置为 "False"​, 其原因为 ReplicaSetCreateError​。 一旦 Deployment 上线完成,就不再考虑其期限。

对失败 Deployment 的操作​** **

可应用于已完成的 Deployment 的所有操作也适用于失败的 Deployment。 可以对其执行扩缩容、回滚到以前的修订版本等操作,或者在需要对 Deployment 的 Pod 模板应用多项调整时,将 Deployment 暂停。

8. 清理策略

可以在 Deployment 中设置 .spec.revisionHistoryLimit​ 字段以指定保留此 Deployment 的多少个旧有 ReplicaSet。其余的 ReplicaSet 将在后台被垃圾回收。 默认情况下此值为 10。

**注意:**将此字段设置为 0 将导致 Deployment 的所有历史记录被清空,因此 Deployment 将无法回滚。

9. 金丝雀部署

如果要使用 Deployment 向用户子集或服务器子集上线版本, 则可以遵循资源管理所描述的金丝雀模式, 创建多个 Deployment,每个版本一个。

金丝雀发布常见的做法是部署一个新应用版本(在 Pod 模板中通过镜像标签指定),保持新旧版本应用同时运行。 这样,新版本在完全发布之前也可以接收实时的生产流量。

10. 编写 Deployment 规范

https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/workload-resources/deployment-v1/

在所有的 Kubernetes 配置中,Deployment 也需要 apiVersion​​,kind​​ 和 metadata​​ 这些配置项。有关配置文件的其他信息,请参考部署 Deployment、 配置容器和使用 kubectl 管理资源等相关文档。

Pod Template

.spec​ 中只有 .spec.template​ 和 .spec.selector​ 是必需的字段。

.spec.template​ 是 pod 的一个模板。它和 pod 的语法规则完全相同,只是这里它是嵌套的,因此不需要 apiVersion​ 或 kind​。

除了 Pod 的必填字段外,Deployment 中的 Pod 模板必须指定适当的标签和适当的重新启动策略。 对于标签,请确保不要与其他控制器重叠。请参考 selector​。

只有 .spec.template.spec.restartPolicy​ 等于 Always​ 才是被允许的,这也是在没有指定时的默认设置。

Replicas

.spec.replicas​ 是可以选字段,指定期望的 pod 数量,默认是 1。

若一个 HorizontalPodAutoscaler(或者其他执行水平扩缩操作的类似 API)在管理 Deployment 的扩缩, 则不要设置 .spec.replicas​。

Selector

.spec.selector​ 是指定本 Deployment 的 Pod 标签选择算符的必需字段。

.spec.selector​ 必须匹配 .spec.template.metadata.labels​,否则请求会被 API 拒绝。

在 API apps/v1​版本中,.spec.selector​ 和 .metadata.labels​ 如果没有设置的话, 不会被默认设置为 .spec.template.metadata.labels​,所以需要明确进行设置。 同时在 apps/v1​版本中,Deployment 创建后 .spec.selector​ 是不可变的。

当 Pod 的标签和选择算符匹配,但其模板和 .spec.template​ 不同时,或者此类 Pod 的总数超过 .spec.replicas​ 的设置时,Deployment 会终结之。 如果 Pod 总数未达到期望值,Deployment 会基于 .spec.template​ 创建新的 Pod。

如果有多个控制器的选择算符发生重叠,则控制器之间会因冲突而无法正常工作。

注意:不应直接创建与此选择算符匹配的 Pod,也不应通过创建另一个 Deployment 或者类似于 ReplicaSet 或 ReplicationController 这类控制器来创建标签与此选择算符匹配的 Pod。 如果这样做,第一个 Deployment 会认为它创建了这些 Pod。 Kubernetes 不会阻止你这么做。

strategy

.spec.strategy​ 策略指定用于用新 Pod 替换旧 Pod 的策略。 .spec.strategy.type​ 可以是 “Recreate” 或 “RollingUpdate”。“RollingUpdate” 是默认值。

  • Recreate

如果 .spec.strategy.type==Recreate​,在创建新 Pod 之前,所有现有的 Pod 会被杀死。

**说明:**这只会确保为了升级而创建新 Pod 之前其他 Pod 都已终止。如果升级一个 Deployment, 所有旧版本的 Pod 都会立即被终止。控制器等待这些 Pod 被成功移除之后, 才会创建新版本的 Pod。如果手动删除一个 Pod,其生命周期是由 ReplicaSet 来控制的, 后者会立即创建一个替换 Pod(即使旧的 Pod 仍然处于 Terminating 状态)。 如果需要一种“最多 n 个”的 Pod 个数保证,你需要考虑使用 StatefulSet。

  • RollingUpdate

Deployment 会在 .spec.strategy.type==RollingUpdate​时,采取滚动更新的方式更新 Pod。可以指定 maxUnavailable​ 和 maxSurge​ 来控制滚动更新过程。

Max Unavailable(最大不可用)

.spec.strategy.rollingUpdate.maxUnavailable​ 是一个可选字段,用来指定 更新过程中不可用的 Pod 的个数上限。该值可以是绝对数字(例如,5),也可以是所需 Pod 的百分比(例如,10%)。百分比值会转换成绝对数并去除小数部分。 如果 .spec.strategy.rollingUpdate.maxSurge​ 为 0,则此值不能为 0。 默认值为 25%。

例如,当此值设置为 30% 时,滚动更新开始时会立即将旧 ReplicaSet 缩容到期望 Pod 个数的 70%。 新 Pod 准备就绪后,可以继续缩容旧有的 ReplicaSet,然后对新的 ReplicaSet 扩容, 确保在更新期间可用的 Pod 总数在任何时候都至少为所需的 Pod 个数的 70%

Max Surge(最大峰值)

.spec.strategy.rollingUpdate.maxSurge​ 是一个可选字段,用来指定可以创建的超出期望 Pod 个数的 Pod 数量。此值可以是绝对数(例如,5)或所需 Pod 的百分比(例如,10%)。 如果 MaxUnavailable​ 为 0,则此值不能为 0。百分比值会通过向上取整转换为绝对数。 此字段的默认值为 25%。

例如,当此值为 30% 时,启动滚动更新后,会立即对新的 ReplicaSet 扩容,同时保证新旧 Pod 的总数不超过所需 Pod 总数的 130%。一旦旧 Pod 被杀死,新的 ReplicaSet 可以进一步扩容, 同时确保更新期间的任何时候运行中的 Pod 总数最多为所需 Pod 总数的 130%。

ProgressDeadlineSeconds

.spec.progressDeadlineSeconds​(进度期限秒数) 是一个可选字段,用于指定系统在报告 Deployment failed 状态之前等待 Deployment 取得进展的秒数。 这类报告会在资源状态中体现为 type: Progressing​、status: False​、 reason: ProgressDeadlineExceeded​。Deployment 控制器将在默认 600 毫秒内持续重试 Deployment。 将来,一旦实现了自动回滚,Deployment 控制器将在探测到这样的条件时立即回滚 Deployment。

如果指定,则此字段值需要大于 .spec.minReadySeconds​ 取值。

MinReadySeconds

.spec.minReadySeconds​ (最短就绪时间)是一个可选字段,用于指定新创建的 Pod 在没有任意容器崩溃情况下的最小就绪时间, 只有超出这个时间 Pod 才被视为可用。默认值为 0(Pod 在准备就绪后立即将被视为可用)。 要了解何时 Pod 被视为就绪, 可参考容器探针。

RevisionHistoryLimit

Deployment 的修订历史记录存储在它所控制的 ReplicaSets 中。

.spec.revisionHistoryLimit​ 是一个可选字段,用来设定出于回滚目的所要保留的旧 ReplicaSet 数量。 这些旧 ReplicaSet 会消耗 etcd 中的资源,并占用 kubectl get rs​ 的输出。 每个 Deployment 修订版本的配置都存储在其 ReplicaSets 中;因此,一旦删除了旧的 ReplicaSet, 将失去回滚到 Deployment 的对应修订版本的能力。 默认情况下,系统保留 10 个旧 ReplicaSet,但其理想值取决于新 Deployment 的频率和稳定性。

更具体地说,将此字段设置为 0 意味着将清理所有具有 0 个副本的旧 ReplicaSet。 在这种情况下,无法撤消新的 Deployment 上线,因为它的修订历史被清除了。

Paused

.spec.paused​​ 是用于暂停和恢复 Deployment 的可选布尔字段。 暂停的 Deployment 和未暂停的 Deployment 的唯一区别是,Deployment 处于暂停状态时, PodTemplateSpec 的任何修改都不会触发新的上线。 Deployment 在创建时是默认不会处于暂停状态。

service

https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/

https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/service-resources/service-v1/

将运行在一组 Pod 上的应用程序公开为网络服务的抽象方法。使用 Kubernetes 无需修改应用程序去使用不熟悉的服务发现机制。 Kubernetes 为 Pod 提供自己的 IP 地址,并为一组 Pod 提供相同的 DNS 名, 并且可以在它们之间进行负载均衡。

Kubernetes Service 是为了管理具有相同功能的一组 Pod 而定义的一种对象,Service 具体的作用和场景如下:

  • 通过 Pod 的 Label Selector 动态匹配后端 endpoint;
  • 将服务和应用解耦合,简化外系统调用 K8S 服务的复杂度,屏蔽 K8S 内部的实现细节;
  • Service 通过 kube-proxy 借助 iptables/ipvs 提供负载均衡的能力,实现反向代理,将请求转发到合适的 Pod 上。

service 工作流程

image

定义 service

https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/service-resources/service-v1/

Service 是软件服务(例如 nginx)的命名抽象,包含代理要侦听的本地端口(例如 80)和一个选择算符, 选择算符用来确定哪些 Pod 将响应通过代理发送的请求。

  • apiVersion​: v1
  • kind​: Service
  • metadata (ObjectMeta)
    标准的对象元数据。
  • spec (ServiceSpec)
    spec 定义 Service 的行为。
  • status(ServiceStatus)
    最近观察到的 Service 状态。由系统填充。只读。

准备环境

需先创建 pod,示例,创建一个 3 副本的 Deployment,即 3 个 Pod,且 Pod 上带有标签“app: nginx”:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1
        ports:
        - containerPort: 80

服务类型

对一些应用的某些部分(如前端),可能希望将其暴露给 Kubernetes 集群外部的 IP 地址。Kubernetes ServiceTypes​ 允许指定你所需要的 Service 类型。

Type​ 的取值以及行为如下:

  • ClusterIP​:通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是你没有为服务显式指定 type​ 时使用的默认值。
  • NodePort​:通过每个节点上的 IP 和静态端口(NodePort​)暴露服务。 为了让节点端口可用,Kubernetes 设置了集群 IP 地址,这等同于你请求 type: ClusterIP​ 的服务。
  • LoadBalancer​:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort​ 服务和 ClusterIP​ 服务上。
  • ExternalName​:通过返回 CNAME​ 记录和对应值,可以将服务映射到 externalName​ 字段的内容(例如,foo.bar.example.com​)。无需创建任何类型代理。

**说明:**kube-dns 1.7 及以上版本或者 CoreDNS 0.0.8 及以上版本才能使用 ExternalName​ 类型。

type​ 字段被设计为嵌套功能 - 每个级别都添加到前一个级别。

还可以使用 Ingress 来暴露自己的服务,Ingress 不是一种服务类型,但它充当集群的入口点。 它可以将路由规则整合到一个资源中,因为它可以在同一 IP 地址下公开多个服务。

image

其中绿色的代表从外向内的访问模式;蓝色的代表从内向外的访问模式,黄色代表集群内部的访问模式。可以看到,除了 ExternalName 类型之外,其余三种类型都是逐层封装而来的。

ClusterIP

这是 K8S 默认的服务类型,只能在 K8S 中进行服务通信。在 ClientIP 中,K8S 会在 Service 创建完毕后提供一个内部 IP 作为 ClientIP 属性,K8S 内部服务可以通过 ClientIP 或者 ServiceName 来访问该服务。

创建 service

以 yaml 方式创建

apiVersion: v1
kind: Service
metadata:
  name: clusterip-nginx-service	# Service的名称
spec:
  selector:          		# Label Selector,选择包含app=nginx标签的Pod
    app: nginx
  type: ClusterIP		# type可不配,不配的话默认就是ClusterIP类型
  # clusterIP: 10.100.13.127	# 可不配,不配的话系统会分配一个随机的IP并保持不变
  ports:
    - targetPort: 80		# Pod的端口
      port: 8080		# Service对外暴露的端口
      protocol: TCP		# 协议类型,TCP、UDP和SCTP,默认类型为TCP

执行命令

kubectl apply -f clusterip-nginx-service.yaml

查看状态
# 查看service类型、端口,选择pod的标签
[root@k8s-deploy yaml]#kubectl get svc -owide
NAME                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE   SELECTOR
clusterip-nginx-service   ClusterIP   10.100.180.205   <none>        8080/TCP   45s   app=nginx
kubernetes                ClusterIP   10.100.0.1       <none>        443/TCP    8d    <none>

# 查看pod标签、IP
[root@k8s-deploy yaml]#kubectl get pod --show-labels -owide 
NAME                               READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES   LABELS
nginx-deployment-66b957f9d-7jhkn   1/1     Running   0          35m   10.200.169.152   10.0.0.42   <none>           <none>            app=nginx,pod-template-hash=66b957f9d
nginx-deployment-66b957f9d-k69d5   1/1     Running   0          35m   10.200.107.212   10.0.0.43   <none>           <none>            app=nginx,pod-template-hash=66b957f9d
nginx-deployment-66b957f9d-s7fdq   1/1     Running   0          35m   10.200.135.202   10.0.0.13   <none>           <none>            app=nginx,pod-template-hash=66b957f9d

# 查看service对应后端pod的IP:端口
[root@k8s-deploy yaml]#kubectl get ep
NAME                      ENDPOINTS                                               AGE
clusterip-nginx-service   10.200.107.212:80,10.200.135.202:80,10.200.169.152:80   69s
kubernetes                10.0.0.11:6443,10.0.0.12:6443,10.0.0.13:6443            8d

创建一个名称为 "clusterip-nginx-service" 的 Service 对象,它会将请求代理到使用 TCP 端口 8080,并且具有标签 app=nginx​ 的 Pod 上。

Kubernetes 为该服务分配一个 IP 地址(有时称为“集群 IP”),该 IP 地址由服务代理使用。

服务选择算符的控制器不断扫描与其选择算符匹配的 Pod,然后将所有更新发布到称为“clusterip-nginx-service”的 Endpoint 对象。

**说明:**Service 能够将一个接收 port​​​ 映射到任意的 targetPort​​​。 默认情况下,targetPort​​​ 将被设置为与 port​​​ 字段相同的值。

验证测试

**注意:**需要在 k8s 集群内部测试

[root@k8s-master1 ~]#curl 10.100.180.205:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

NodePort

NodePort 类型的 Service 可以让 Kubernetes 集群每个节点上保留一个相同的端口, 外部访问连接首先访问节点 IP:Port(端口默认值:30000-32767),然后将这些连接转发给服务对应的 Pod。

image

创建 service

以 yaml 方式

apiVersion: v1
kind: Service
metadata:
  name: nodeport-nginx-service
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
    # 默认情况下,为了方便起见,targetPort 被设置为与port字段相同的值。
    - port: 80
      targetPort: 80
      # 可选字段
      # 默认情况下,为了方便起见,Kubernetes 控制平面会从某个范围内分配一个端口号(默认:30000-32767)
      nodePort: 30120

执行

kubectl apply -f nodeport-nginx-service.yaml
查看状态
# 查看service类型、映射端口
[root@k8s-deploy yaml]#kubectl get svc -owide
NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
kubernetes               ClusterIP   10.100.0.1      <none>        443/TCP        8d    <none>
nodeport-nginx-service   NodePort    10.100.40.40    <none>        80:30120/TCP   6s    app=nginx

# 查看pod标签、IP
[root@k8s-deploy yaml]#kubectl get pod --show-labels -owide
NAME                               READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES   LABELS
nginx-deployment-66b957f9d-7jhkn   1/1     Running   0          3m48s   10.200.169.152   10.0.0.42   <none>           <none>            app=nginx,pod-template-hash=66b957f9d
nginx-deployment-66b957f9d-k69d5   1/1     Running   0          3m48s   10.200.107.212   10.0.0.43   <none>           <none>            app=nginx,pod-template-hash=66b957f9d
nginx-deployment-66b957f9d-s7fdq   1/1     Running   0          3m48s   10.200.135.202   10.0.0.13   <none>           <none>            app=nginx,pod-template-hash=66b957f9d

# 查看service对应后端pod的IP:端口
[root@k8s-deploy yaml]#kubectl get ep
NAME                     ENDPOINTS                                               AGE
kubernetes               10.0.0.11:6443,10.0.0.12:6443,10.0.0.13:6443            8d
nodeport-nginx-service   10.200.107.212:80,10.200.135.202:80,10.200.169.152:80   42s

创建一个名称为 "nodeport-nginx-service" 的 Service 对象,它会将 TCP 10.100.40.40:80(集群内部访问)/宿主机 ip:30120(外部访问)请求代理到后端标签 app=nginx​ 的 Pod 上。

验证测试
  • 集群内部访问 10.100.225.73:80
[root@k8s-master1 ~]#curl 10.100.225.73:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

  • 浏览器访问集群任意一宿主机 ip:30120

image

LoadBalancer

LoadBalancer 类型的 service 是可以实现集群外部访问服务的另外一种解决方案。不过并不是所有的 k8s 集群都会支持,大多是在公有云托管集群中会支持该类型。负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 Service 的 status.loadBalancer​字段被发布出去。

示例:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 192.0.2.127

来自外部负载均衡器的流量将直接重定向到后端 Pod 上,不过实际它们是如何工作的,这要依赖于云提供商。

ExternalName

ExternalName 类型的 service 方式。该类型的好处是内部服务访问外部服务的时候是通过别名来访问的,屏蔽了外部服务的真实信息,外部服务对内部服务透明,外部服务的修改基本上不会影响到内部服务的访问,做到了内部服务和外部服务解耦合。

示例,以下 Service 定义将 prod​ 名称空间中的 my-service​ 服务映射到 my.database.example.com​:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

**说明:**ExternalName 服务接受 IPv4 地址字符串,但作为包含数字的 DNS 名称,而不是 IP 地址。 类似于 IPv4 地址的外部名称不能由 CoreDNS 或 ingress-nginx 解析,因为外部名称旨在指定规范的 DNS 名称。 要对 IP 地址进行硬编码,请考虑使用无头 Services。

说明

定义端口名称

Pod 中的端口定义是有名字的,你可以在 Service 的 targetPort​​​ 属性中引用这些名称。 例如,可以通过以下方式将 Service 的 targetPort​​​ 绑定到 Pod 端口:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app.kubernetes.io/name: proxy
spec:
  containers:
  - name: nginx
    image: nginx:stable
    ports:
      - containerPort: 80
        name: http-web-svc

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app.kubernetes.io/name: proxy
  ports:
    - name: name-of-service-port
      protocol: TCP
      port: 80
      targetPort: http-web-svc	#可配置对应pod中containerPort(80),也可配置对应的name(http-web-svc)
多端口 service

对于某些服务,你需要公开多个端口。 Kubernetes 允许你在 Service 对象上配置多个端口定义。 为服务使用多个端口时,必须提供所有端口名称,以使它们无歧义。

示例:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
    - name: https
      protocol: TCP
      port: 443
      targetPort: 9377

与一般的 Kubernetes 名称一样,端口名称只能包含小写字母数字字符和 -​​。 端口名称还必须以字母数字字符开头和结尾。

例如,名称 123-abc​​​​​ 和 web​​​​​ 有效,但是 123_abc​​​​​ 和 -web​​​​​ 无效。

无选择算符的 service

由于选择算符的存在,服务最常见的用法是为 Kubernetes Pod 的访问提供抽象, 但是当与相应的 EndpointSlices 对象一起使用且没有选择算符时, 服务也可以为其他类型的后端提供抽象,包括在集群外运行的后端。

在以下这些场景中,都能够定义没有选择算符的 Service:

  • 希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。
  • 希望服务指向另一个 Namespace 中或其它集群中的服务。
  • 正在将工作负载迁移到 Kubernetes。在评估该方法时,仅在 Kubernetes 中运行一部分后端。
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

由于此服务没有选择算符,因此不会自动创建相应的 EndpointSlice(和旧版 Endpoint)对象。 可以通过手动添加 EndpointSlice 对象,将服务映射到运行该服务的网络地址和端口:

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: my-service-1 # 按惯例将服务的名称用作 EndpointSlice 名称的前缀
  labels:
    # 应设置 "kubernetes.io/service-name"标签。
    # 设置其值以匹配服务的名称
    kubernetes.io/service-name: my-service
addressType: IPv4
ports:
  - name: '' # 留空,因为 port 9376 未被 IANA 分配为已注册端口
    appProtocol: http
    protocol: TCP
    port: 9376
endpoints:
  - addresses:
      - "10.4.5.6" # 此列表中的 IP 地址可以按任何顺序显示
      - "10.1.2.3"

Headless Services

有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP​​)的值为 "None"​​ 来创建 Headless​​ Service。

可以使用一个无头 Service 与其他服务发现机制进行接口,而不必与 Kubernetes 的实现捆绑在一起。

对于无头 Services​​ 并不会分配 Cluster IP,kube-proxy 不会处理它们, 而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了选择算符。

带选择算符的服务

对定义了选择算符的无头服务,Kubernetes 控制平面在 Kubernetes API 中创建 EndpointSlice 对象, 并且修改 DNS 配置返回 A 或 AAA 条记录(IPv4 或 IPv6 地址),通过这个地址直接到达 Service​​ 的后端 Pod 上。

无选择算符的服务

对没有定义选择算符的无头服务,控制平面不会创建 EndpointSlice 对象。 然而 DNS 系统会查找和配置以下之一:

  • 对于 type: ExternalName​​ 服务,查找和配置其 CNAME 记录

  • 对所有其他类型的服务,针对 Service 的就绪端点的所有 IP 地址,查找和配置 DNS A / AAAA 条记录

    • 对于 IPv4 端点,DNS 系统创建 A 条记录。
    • 对于 IPv6 端点,DNS 系统创建 AAAA 条记录。

configmap

https://kubernetes.io/zh-cn/docs/concepts/configuration/configmap/

ConfigMap 是一种用于存储应用所需配置信息的资源类型,用于保存配置数据的键值对,可以用来保存单个属性,也可以用来保存配置文件。

通过 ConfigMap 可以方便的做到配置解耦,使得不同环境有不同的配置。

configmap 应用场景:

  • 通过 Configmap 给 pod 定义全局环境变量
  • 通过 Configmap 给 pod 传递命令行参数,如 mysql -u -p 中的账户名密码可以通过 configmap 传递
  • 通过 Configmap 给 pod 中的容器服务提供配置文件,配置文件以挂载到容器的形式使用

注意:

  • Configmap 需要在使用 pod 之前创建
  • pod 只能使用位于同一个 namespace 的 Configmap,及 Configmap 不能跨 namespace 使用
  • ConfigMap 并不提供保密或者加密功能。 如果想存储的数据是机密的,请使用 Secret, 或者使用其他第三方工具来保证数据的私密性。
  • ConfigMap 中保存的数据不可超过 1M

创建 configmap

apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap-test
data:
  # 类属性键;每一个键都映射到一个简单的值
  property_1: Hello
  property_2: World

查看

# 创建
[root@k8s-deploy yaml]#kubectl apply -f configmap.yaml 
configmap/configmap-test created

# 查看configmap
[root@k8s-deploy yaml]#kubectl get cm
NAME               DATA   AGE
configmap-test     2      15s
kube-root-ca.crt   1      8d

[root@k8s-deploy yaml]#kubectl describe cm configmap-test
Name:         configmap-test
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
property_1:
----
Hello
property_2:
----
World

BinaryData
====

Events:  <none>

可以用以下四种方式来使用 ConfigMap 配置 Pod 中的容器:

  1. 在容器命令和参数内
  2. 容器的环境变量
  3. 在只读卷里面添加一个文件,让应用来读取
  4. 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap

在环境变量中引用 ConfigMap

ConfigMap 最为常见的使用方式就是在环境变量和 Volume 中引用。

例如下面例子中,引用了 configmap-test 的 property_1,将其作为环境变量 EXAMPLE_PROPERTY_1 的值,这样容器启动后里面 EXAMPLE_PROPERTY_1 的值就是 property_1 的值,即**“Hello”**。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx:1.16.1
    name: container-0
    resources:
      limits:
        cpu: 100m
        memory: 200Mi
      requests:
        cpu: 100m
        memory: 200Mi
    env:
    # 定义环境变量
    - name: EXAMPLE_PROPERTY_1	# 请注意这里和 ConfigMap 中的键名是不一样的
      valueFrom:
        configMapKeyRef:	# 引用ConfigMap
          name: configmap-test	# 这个值来自 ConfigMap
          key: property_1	# 需要取值的键
  imagePullSecrets:
  - name: default-secret

验证

# 获取创建nginx的pod
[root@k8s-deploy yaml]#kubectl get pod
NAME                               READY   STATUS    RESTARTS   AGE
nginx                              1/1     Running   0          38s
nginx-deployment-66b957f9d-7jhkn   1/1     Running   0          145m
nginx-deployment-66b957f9d-k69d5   1/1     Running   0          145m
nginx-deployment-66b957f9d-s7fdq   1/1     Running   0          145m

# 进入容器,查看EXAMPLE_PROPERTY_1值
[root@k8s-deploy yaml]#kubectl exec -it nginx sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# echo $EXAMPLE_PROPERTY_1
Hello
# 

在 Volume 中引用 ConfigMap

在 Volume 中引用 ConfigMap,就是通过文件的方式直接将 ConfigMap 的每条数据填入 Volume,每条数据是一个文件,键就是文件名,键值就是文件内容。

如下示例中,创建一个名为 vol-configmap 的 Volume,这个 Volume 引用名为“configmap-test”的 ConfigMap,再将 Volume 挂载到容器的“/tmp”路径下。Pod 创建成功后,在容器的“/tmp”路径下,就有两个文件 p1 和 p2,它们的值分别为“Hello”和“World”。

apiVersion: v1
kind: Pod
metadata:
  name: nginx-volume
spec:
  containers:
  - image: nginx:1.16.1
    name: container-0
    resources:
      limits:
        cpu: 100m
        memory: 200Mi
      requests:
        cpu: 100m
        memory: 200Mi
    volumeMounts:
    - name: vol-configmap		# 挂载名为vol-configmap的Volume
      mountPath: "/tmp"
  imagePullSecrets:
  - name: default-secret
  volumes:
  # 你可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
  - name: vol-configmap
    configMap:				# 引用ConfigMap
      # 提供想要挂载的 ConfigMap 的名字
      name: configmap-test
      # 来自 ConfigMap 的一组键,将被创建为文件,如果不配置items,则 ConfigMap 中的每个键都会变成一个与该键同名的文件。path为挂载点名称,key为文件内容
      items:
      - key: property_1
        path: p1
      - key: property_2
        path: p2

验证

[root@k8s-deploy yaml]#kubectl apply -f volume-configmap.yaml 
pod/nginx-volume created

[root@k8s-deploy yaml]#kubectl get pod
NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-66b957f9d-7jhkn   1/1     Running   0          3h5m
nginx-deployment-66b957f9d-k69d5   1/1     Running   0          3h5m
nginx-deployment-66b957f9d-s7fdq   1/1     Running   0          3h5m
nginx-volume                       1/1     Running   0          14s

[root@k8s-deploy yaml]#kubectl exec -it nginx-volume bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-volume:/# more /tmp/p1 
Hello
root@nginx-volume:/# more /tmp/p2
World
root@nginx-volume:/#

被挂载的 ConfigMap 内容会自动更新

当卷中使用的 ConfigMap 被更新时,所投射的键最终也会被更新。 kubelet 组件会在每次周期性同步时检查所挂载的 ConfigMap 是否为最新。 不过,kubelet 使用的是其本地的高速缓存来获得 ConfigMap 的当前值。 高速缓存的类型可以通过 KubeletConfiguration 结构. 的 ConfigMapAndSecretChangeDetectionStrategy​ 字段来配置。

ConfigMap 既可以通过 watch 操作实现内容传播(默认形式),也可实现基于 TTL 的缓存,还可以直接经过所有请求重定向到 API 服务器。 因此,从 ConfigMap 被更新的那一刻算起,到新的主键被投射到 Pod 中去, 这一时间跨度可能与 kubelet 的同步周期加上高速缓存的传播延迟相等。 这里的传播延迟取决于所选的高速缓存类型 (分别对应 watch 操作的传播延迟、高速缓存的 TTL 时长或者 0)。

以环境变量方式使用的 ConfigMap 数据不会被自动更新。 更新这些数据需要重新启动 Pod。

验证

# 修改property_1为Hello_1,property_2为World_1

[root@k8s-deploy yaml]#kubectl apply -f configmap.yaml 
configmap/configmap-test configured
[root@k8s-deploy yaml]#kubectl describe cm configmap-test
Name:         configmap-test
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
property_1:
----
Hello_1
property_2:
----
World_1

BinaryData
====

Events:  <none>

[root@k8s-deploy yaml]#kubectl exec -it nginx-volume bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-volume:/# more /tmp/p1 
Hello_1
root@nginx-volume:/# more /tmp/p2 
World_1

secret

https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/

Secret 是一种加密存储的资源对象,可以将认证信息、证书、私钥等保存在 Secret 中,而不需要把这些敏感数据暴露到镜像或者 Pod 定义中,从而更加安全和灵活。

Secret 与 ConfigMap 非常像,都是 key-value 键值对形式,使用方式也相同,不同的是 Secret 会加密存储,所以适用于存储敏感信息。

应用场景:

  1. 作为挂载到一个或多个容器上的卷 中的文件。
  2. 作为容器的环境变量。
  3. 由 kubelet 在为 Pod 拉取镜像时使用。

注意:

  • Secret 对象的名称必须是合法的 DNS 子域名。
  • 在为创建 Secret 编写配置文件时,可以设置 data​ 与/或 stringData​ 字段。 data​ 和 stringData​ 字段都是可选的。data​ 字段中所有键值都必须是 base64 编码的字符串。如果不希望执行这种 base64 字符串的转换操作,可以选择设置 stringData​ 字段,其中可以使用任何字符串作为其取值。
  • data​ 和 stringData​ 中的键名只能包含字母、数字、-​、_​ 或 .​ 字符。 stringData​ 字段中的所有键值对都会在内部被合并到 data​ 字段中。 如果某个主键同时出现在 data​ 和 stringData​ 字段中,stringData​ 所指定的键值具有高优先级。

secret 挂载流程

image

Base64 编码

Secret 与 ConfigMap 相同,是以键值对形式保存数据,所不同的是在创建时,data 类型 Secret 的 Value 必须使用 Base64 编码。

对字符串进行 Base64 编码,可以直接使用 echo -n 要编码的内容 | base64​命令即可,示例如下:

[root@k8s-deploy yaml]#echo -n "3306" | base64
MzMwNg==

创建 Secret

如下示例中定义的 Secret 中包含两条 Key-Value。

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
data:
  key1: aGVsbG8gd29ybGQ=   # "hello world" Base64编码后的值
  key2: MzMwNg==           # "3306" Base64编码后的值

查看 secret

[root@k8s-deploy yaml]#kubectl apply -f secret.yaml 
secret/mysecret created

[root@k8s-deploy yaml]#kubectl get secret
NAME       TYPE     DATA   AGE
mysecret   Opaque   2      34s

[root@k8s-deploy yaml]#kubectl describe secret mysecret
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
key2:  4 bytes
key1:  11 bytes

在环境变量中引用 Secret

Secret 最常见的用法是作为环境变量注入到容器中,如下示例。

apiVersion: v1
kind: Pod
metadata:
  name: env-nginx
spec:
  containers:
  - image: nginx:1.16.1
    name: container-0
    resources:
      limits:
        cpu: 100m
        memory: 200Mi
      requests:
        cpu: 100m
        memory: 200Mi
    env:
    - name: key
      valueFrom:
        secretKeyRef:		# 引用Secret
          name: mysecret
          key: key1
  imagePullSecrets:
  - name: default-secret

进入 Pod 容器中,可以查看环境变量 key 的值,base64 解码后为 hello world​。

[root@k8s-deploy yaml]#kubectl get pod
NAME                               READY   STATUS    RESTARTS   AGE
env-nginx                          1/1     Running   0          39s

[root@k8s-deploy yaml]#kubectl exec -it env-nginx bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@env-nginx:/# echo $key
hello world

在 Volume 中引用 Secret

在 Volume 中引用 Secret,就是通过文件的方式直接将 Secret 的每条数据填入 Volume,每条数据是一个文件,键就是文件名,键值就是文件内容。

如下示例中,创建一个名为 vol-secret 的 Volume,这个 Volume 引用名为 mysecret​的 Secret,再将 Volume 挂载到容器的 /tmp​路径下。Pod 创建成功后,在容器的 /tmp​路径下,就有两个文件 key1 和 key2。

apiVersion: v1
kind: Pod
metadata:
  name: volume-nginx
spec:
  containers:
  - image: nginx:1.16.1
    name: container-0
    resources:
      limits:
        cpu: 100m
        memory: 200Mi
      requests:
        cpu: 100m
        memory: 200Mi
    volumeMounts:
    - name: vol-secret              # 挂载名为vol-secret的Volume
      mountPath: "/tmp"
  imagePullSecrets:
  - name: default-secret
  volumes:
  - name: vol-secret
    secret:                         # 引用Secret
      secretName: mysecret

进入 Pod 容器中,可以在/tmp 目录下发现 key1 和 key2 两个文件,并看到文件中的值是 base64 解码后的值,分别为 hello world​和 3306​。

[root@k8s-deploy yaml]#kubectl get pod
NAME                               READY   STATUS    RESTARTS   AGE
env-nginx                          1/1     Running   0          8m6s
volume-nginx                       1/1     Running   0          4s

[root@k8s-deploy yaml]#kubectl exec -it volume-nginx bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@volume-nginx:/# more /tmp/key1
hello world
root@volume-nginx:/# more /tmp/key2
3306

secret 类型

创建 Secret 时,可以使用 Secret 资源的 type​ 字段,或者与其等价的 kubectl​ 命令行参数为其设置类型。 Secret 类型有助于对 Secret 数据进行编程处理。

Kubernetes 提供若干种内置的类型,用于一些常见的使用场景。 针对这些类型,Kubernetes 所执行的合法性检查操作以及对其所实施的限制各不相同。

内置类型 用法
Opaque 用户定义的任意数据
kubernetes.io/service-account-token 服务账号令牌
kubernetes.io/dockercfg ~/.dockercfg​ 文件的序列化形式
kubernetes.io/dockerconfigjson ~/.docker/config.json​ 文件的序列化形式
kubernetes.io/basic-auth 用于基本身份认证的凭据
kubernetes.io/ssh-auth 用于 SSH 身份认证的凭据
kubernetes.io/tls 用于 TLS 客户端或者服务器端的数据
bootstrap.kubernetes.io/token 启动引导令牌数据

详细信息查看:https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/#secret-types

三、掌握基于 NFS 实现 pod 数据持久化的使用方式,测试 emptyDir、hostPath 的使用

https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/

NFS

nfs 卷能将 NFS (网络文件系统) 挂载到 Pod 中。nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。

部署 nfs 服务器

主机:10.0.0.101(harbor1)

# 安装nfs服务端
apt install -y nfs-kernel-server nfs-common

# 在/etc/exports末尾添加
echo "/data *(rw,sync,no_root_squash,no_subtree_check)" >> /etc/exports

# 配置生效
exportfs -r

查看状态

[root@harbor1 ~]#exportfs -v
/data         	<world>(rw,wdelay,no_root_squash,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)

创建 NFS 卷

# k8s集群需安装nfs客户端
apt install -y nfs-common

创建 pod

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: nginx:1.16.1
    name: test-container
    volumeMounts:
    - mountPath: /my-nfs-data	# 挂载至容器内目录
      name: test-volume		# 使用挂载卷名称
  volumes:
  - name: test-volume		# 定义卷名称
    nfs:
      server: 10.0.0.101	# nfs服务器,可以配置IP,也可配置域名
      path: /data		# nfs目录,须在nfs挂载目录中
      readOnly: true		# 只读权限

验证

# nfs服务器/data目录下文件
[root@harbor1 ~]#ls -l /data/
total 0
drwxr-xr-x 2            10000            10000  6 Jan 17 12:09 ca_download
drwxr-xr-x 2            10000            10000  6 Jan 17 12:09 chart_storage
drwx------ 3 systemd-coredump systemd-coredump 18 Jan 17 12:09 database
drwxr-xr-x 2            10000            10000  6 Jan 26 13:45 job_logs
drwxr-xr-x 2 systemd-coredump systemd-coredump 22 Jan 26 22:57 redis
drwxr-xr-x 3            10000            10000 20 Jan 17 12:46 registry
drwxr-xr-x 2            10000            10000  6 Jan 17 12:09 scandata_exports
drwxr-xr-x 6 root             root             58 Jan 17 12:09 secret
drwxr-xr-x 4 root             root             34 Jan 17 12:09 trivy-adapter

# 进入容器,查看/my-nfs-data目录下文件
[root@k8s-deploy yaml]#kubectl get pod
NAME                               READY   STATUS    RESTARTS   AGE
test-pd                            1/1     Running   0          4m7s

[root@k8s-deploy yaml]#kubectl exec -it test-pd bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@test-pd:/# ls -l /my-nfs-data/
total 0
drwxr-xr-x 2 10000 10000  6 Jan 17 04:09 ca_download
drwxr-xr-x 2 10000 10000  6 Jan 17 04:09 chart_storage
drwx------ 3   999   999 18 Jan 17 04:09 database
drwxr-xr-x 2 10000 10000  6 Jan 26 05:45 job_logs
drwxr-xr-x 2   999   999 22 Jan 26 15:02 redis
drwxr-xr-x 3 10000 10000 20 Jan 17 04:46 registry
drwxr-xr-x 2 10000 10000  6 Jan 17 04:09 scandata_exports
drwxr-xr-x 6 root  root  58 Jan 17 04:09 secret
drwxr-xr-x 4 root  root  34 Jan 17 04:09 trivy-adapter
# 只读,不可写
root@test-pd:/my-nfs-data# echo 'pod' > 1.log 
bash: 1.log: Read-only file system

进入 Pod 容器中,可以看到容器/my-nfs-data 目录下文件与 nfs 服务器/data 目录文件相同。

emptydir

当 Pod 分派到某个节点上时,emptyDir​ 卷会被创建,并且在 Pod 在该节点上运行期间,卷一直存在。 就像其名称表示的那样,卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir​ 卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir​ 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir​ 卷中的数据也会被永久删除。

image

emptydir 示例:

apiVersion: v1
kind: Pod
metadata:
  name: emptydir-pd
spec:
  containers:
  - image: nginx:1.16.1
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 100Mi

验证

# 查看pod所在宿主机IP
[root@k8s-deploy yaml]#kubectl get pod -owide
NAME                               READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
emptydir-pd                        1/1     Running   0          4s    10.200.135.212   10.0.0.13   <none>           <none>
# 进入容器创建emptpydir-test文件
[root@k8s-deploy yaml]#kubectl exec -it emptydir-pd bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@emptydir-pd:/# ls /cache/
root@emptydir-pd:/# echo 'emptydir-pod' >> /cache/emptpydir-test

# 进入宿主机,查看emptpydir-test文件内容
[root@k8s-master3 ~]#find / -name emptpydir-test
/var/lib/kubelet/pods/c5e8d5a6-f898-4309-baee-d6287e703ae2/volumes/kubernetes.io~empty-dir/cache-volume/emptpydir-test
[root@k8s-master3 ~]#cat /var/lib/kubelet/pods/c5e8d5a6-f898-4309-baee-d6287e703ae2/volumes/kubernetes.io~empty-dir/cache-volume/emptpydir-test
emptydir-pod

# 删除容器,宿主机emptpydir-test文件也跟随删除
[root@k8s-deploy yaml]#kubectl delete -f emptydir-pd.yaml 
pod "emptydir-pd" deleted
[root@k8s-deploy yaml]#kubectl get pod
No resources found in default namespace.
[root@k8s-master3 ~]#cat /var/lib/kubelet/pods/c5e8d5a6-f898-4309-baee-d6287e703ae2/volumes/kubernetes.io~empty-dir/cache-volume/emptpydir-test
cat: /var/lib/kubelet/pods/c5e8d5a6-f898-4309-baee-d6287e703ae2/volumes/kubernetes.io~empty-dir/cache-volume/emptpydir-test: No such file or directory

创建 pod 后生成 emptydir 本地临时卷,删除 pod 后 emptydir 本地临时卷被回收。

hostpath

hostPath​ 卷能将主机节点文件系统上的文件或目录挂载到 Pod 中。 pod 删除时,hostpath 卷不会删除。

注意

  • HostPath 卷存在许多安全风险,最佳做法是尽可能避免使用 HostPath。 当必须使用 HostPath 卷时,它的范围应仅限于所需的文件或目录,并以只读方式挂载。
  • 如果通过 AdmissionPolicy 限制 HostPath 对特定目录的访问,则必须要求 volumeMounts​ 使用 readOnly​ 挂载以使策略生效。

​**hostPath 应用场景:**​

  • 运行一个需要访问 Docker 内部机制的容器;可使用 hostPath​ 挂载 /var/lib/docker​ 路径。
  • 在容器中运行 cAdvisor 时,以 hostPath​ 方式挂载 /sys​。
  • 允许 Pod 指定给定的 hostPath​ 在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在。

除了必需的 path​ 属性之外,可选择为 hostPath​ 卷指定 type​。

type 值参考:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/#hostpath

hostpath 示例:

apiVersion: v1
kind: Pod
metadata:
  name: hostpath-pd
spec:
  containers:
  - image: nginx:1.16.1
    name: test-container
    volumeMounts:
    - mountPath: /hostpath-pd		# 容器中挂载位置
      name: hostpath-volume
  volumes:
  - name: hostpath-volume
    hostPath:
      # 宿主上目录位置
      path: /data

验证

# 查看pod所在宿主机IP
[root@k8s-deploy yaml]#kubectl get pod -owide
NAME                               READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
hostpath-pd                        1/1     Running   0          2s    10.200.135.214   10.0.0.13   <none>           <none>

# 进入容器,创建hostpath-test文件
[root@k8s-deploy yaml]#kubectl exec -it hostpath-pd bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@hostpath-pd:/# echo 'hostpath' >> /hostpath-pd/hostpath-test

# 进入宿主机,查看hostpath-test文件内容
[root@k8s-master3 data]#cat /data/hostpath-test 
hostpath

# 删除容器
[root@k8s-deploy yaml]#kubectl delete -f hostpath-pd.yaml 
pod "hostpath-pd" deleted
[root@k8s-deploy yaml]#kubectl get pod
No resources found in default namespace.

# 宿主机hostpath-test文件依然存在,未被删除
[root@k8s-master3 data]#cat /data/hostpath-test 
hostpath

创建 pod 后挂载 hostpath 本地存储卷,删除 pod 后 hostpath 本地存储卷不会删除。

四、实现基于 Secret 实现 nginx 的 tls 认证、并实现私有仓库镜像的下载认证

https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/#tls-secret

tls 认证

自签名证书,创建 secret

mkdir -p /data/certs
cd /data/certs
openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3560 -nodes -subj '/CN=www.ca.com'
openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN=www.mysite.com'
openssl x509 -req -sha256 -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
# 创建secret
kubectl create secret tls myserver-tls-key --cert=./server.crt --key=./server.key -n myserver

查看 secret

[root@k8s-deploy certs]#kubectl get secret -n myserver
NAME               TYPE                DATA   AGE
myserver-tls-key   kubernetes.io/tls   2      3m48s
[root@k8s-deploy certs]#kubectl describe secret myserver-tls-key -n myserver
Name:         myserver-tls-key
Namespace:    myserver
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/tls

Data
====
tls.crt:  1667 bytes
tls.key:  3272 bytes

创建 web 服务 nginx 并使用证书

# 创建configmap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: myserver
data:
  default: |
    server {
      listen  80;
      listen  443 ssl;
      server_name     www.mysite.com;
      ssl_certificate         /etc/nginx/conf.d/certs/tls.crt;
      ssl_certificate_key     /etc/nginx/conf.d/certs/tls.key;
      location / {
          root  /usr/share/nginx/html;
          index index.html index.htm;
          if ($scheme = http) {
              rewrite / https://www.mysite.com permanent;
          }
          #if (-e $request_filename) {
          #    rewrite ^/(.*) /index.html last;
          #}
      }
    }    

---
# 创建deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-nginx-deploy
  namespace: myserver
  labels:
    app: myserver-nginx-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myserver-nginx
  template:
    metadata:
      labels:
        app: myserver-nginx
    spec:
      containers:
      - name: myserver-nginx
        image: nginx:1.19.1
        ports:
          - containerPort: 80
        volumeMounts:
          - name: nginx-config			# nginx-config卷名称
            mountPath: /etc/nginx/conf.d	# 容器中挂载所在目录
          - name: myserver-tls-key		# myserver-tls-key名称
            mountPath: /etc/nginx/conf.d/certs	# 容器中挂载所在目录
      volumes:
      - name: nginx-config			# 定义卷名称
        configMap:				# 引用configmap
          name: nginx-config			# 对应ConfigMap中名称
          items:
            - key: default			# ConfigMap中default键
              path: mysite.conf			# 挂载文件名称,文件内容为default的值
      - name: myserver-tls-key
        secret:					# 引用secret
          secretName: myserver-tls-key		# 未设置itmes,默认使用所有itmes中key、path数据,key(如secret中tls.crt值)为文件内容,path为文件名(tls.crt)

---
# 创建service
apiVersion: v1
kind: Service
metadata:
  name: nmyserver-nginx-service
  namespace: myserver
spec:
  type: NodePort
  selector:
    app: myserver-nginx
  ports:
    - name: http				# 名称http
      protocol: TCP				# TCP协议
      port: 80					# Service端口
      targetPort: 80				# pod端口
      nodePort: 30019				# 宿主机端口
    - name: https				# 名称https
      protocol: TCP
      port: 443
      targetPort: 443
      nodePort: 30020

查看状态

[root@k8s-deploy yaml]#kubectl apply -f myserver-nginx.yaml 
configmap/nginx-config created
deployment.apps/myserver-nginx-deploy created
service/nmyserver-nginx-service created
[root@k8s-deploy yaml]#kubectl get svc -n myserver
NAME                      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
nmyserver-nginx-service   NodePort   10.100.79.198   <none>        80:30019/TCP,443:30020/TCP   15s
[root@k8s-deploy yaml]#kubectl get pod -n myserver -owide
NAME                                     READY   STATUS    RESTARTS        AGE    IP               NODE        NOMINATED NODE   READINESS GATES
myserver-nginx-deploy-77fd49884f-hnntn   1/1     Running   0               25s    10.200.169.154   10.0.0.42   <none>           <none>
myserver-nginx-deploy-77fd49884f-p96p4   1/1     Running   0               25s    10.200.107.214   10.0.0.43   <none>           <none>
myserver-nginx-deploy-77fd49884f-x7lcv   1/1     Running   0               25s    10.200.135.216   10.0.0.13   <none>           <none>

测试,https 访问集群任一主机 IP:30020

image

配置负载均衡

#vim /etc/haproxy/haproxy.cfg
# 文件末尾添加如下配置
...
listen myserver_nginx_http_80
    bind 10.0.0.10:80
    mode tcp
    server 10.0.0.11 10.0.0.11:30019 check inter 3s fall 3 rise 5
    server 10.0.0.12 10.0.0.12:30019 check inter 3s fall 3 rise 5
    server 10.0.0.13 10.0.0.13:30019 check inter 3s fall 3 rise 5
    server 10.0.0.41 10.0.0.41:30019 check inter 3s fall 3 rise 5
    server 10.0.0.42 10.0.0.42:30019 check inter 3s fall 3 rise 5
    server 10.0.0.43 10.0.0.43:30019 check inter 3s fall 3 rise 5


listen myserver_nginx_https_443
    bind 10.0.0.10:443
    mode tcp
    balance source				#源地址hash
    server 10.0.0.11 10.0.0.11:30020 check inter 3s fall 3 rise 5
    server 10.0.0.12 10.0.0.12:30020 check inter 3s fall 3 rise 5
    server 10.0.0.13 10.0.0.13:30020 check inter 3s fall 3 rise 5
    server 10.0.0.41 10.0.0.41:30020 check inter 3s fall 3 rise 5
    server 10.0.0.42 10.0.0.42:30020 check inter 3s fall 3 rise 5
    server 10.0.0.43 10.0.0.43:30020 check inter 3s fall 3 rise 5

查看端口

# 重启haproxy
systemctl reload haproxy.service
[root@k8s-ha1 ~]#ss -ntl|grep 10.0.0.10:
LISTEN  0        4096           10.0.0.10:6443           0.0.0.0:*          
LISTEN  0        4096           10.0.0.10:80             0.0.0.0:*          
LISTEN  0        4096           10.0.0.10:443            0.0.0.0:* 

验证

  • 配置 host 域名解析
10.0.0.10 www.mysite.com

image

  • 查看自签名证书

image

  • 进入首页

image

私有仓库认证

创建 sercet

  • 使用命令创建
kubectl create secret docker-registry keyName \
--docker-server=registry.cn-shanghai.aliyuncs.com \
--docker-username=USER \
--docker-password=PASSWORD
  • 使用 docker 认证文件创建
# 登录私有仓库,登录成功后,认证信息保存至/root/.docker/config.json文件
docker login --username=USER registry.cn-shanghai.aliyuncs.com		# 阿里云账号名
# 创建secret
kubectl create secret generic aliyun-registry-image-pull-key \
--from-file=.dockerconfigjson=/root/.docker/config.json \
--type=kubernetes.io/dockerconfigjson \
-n myserver

查看 secret

# 查看secret
[root@k8s-deploy yaml]#kubectl get secret -n myserver
NAME                             TYPE                             DATA   AGE
aliyun-registry-image-pull-key   kubernetes.io/dockerconfigjson   1      59s
myserver-tls-key                 kubernetes.io/tls                2      2h

# 查看aliyun-registry-image-pull-key secret信息
[root@k8s-deploy yaml]#kubectl describe secret aliyun-registry-image-pull-key -n myserver
Name:         aliyun-registry-image-pull-key
Namespace:    myserver
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/dockerconfigjson

Data
====
.dockerconfigjson:  162 bytes

# 查看aliyun-registry-image-pull-key secret内容
[root@k8s-deploy yaml]#kubectl get secret aliyun-registry-image-pull-key -n myserver -oyaml
apiVersion: v1
data:
  .dockerconfigjson: ewoJIFTbj......iCgkJfQoJfQp9
kind: Secret
metadata:
  creationTimestamp: "2023-01-27T11:03:52Z"
  name: aliyun-registry-image-pull-key
  namespace: myserver
  resourceVersion: "626544"
  uid: d69009a9-c89a-45d4-8e90-ab5f36ce9a3b
type: kubernetes.io/dockerconfigjson

上传镜像至阿里云私有仓库

[root@k8s-deploy yaml]#docker tag nginx:1.18.0 registry.cn-shanghai.aliyuncs.com/shichu/baseimages:nginx-1.18.0

[root@k8s-deploy yaml]#docker push registry.cn-shanghai.aliyuncs.com/shichu/baseimages:nginx-1.18.0
The push refers to repository [registry.cn-shanghai.aliyuncs.com/shichu/baseimages]
4fa6704c8474: Pushed 
4fe7d87c8e14: Pushed 
6fcbf7acaafd: Pushed 
f3fdf88f1cb7: Pushed 
7e718b9c0c8c: Pushed 
nginx-1.18.0: digest: sha256:9b0fc8e09ae1abb0144ce57018fc1e13d23abd108540f135dc83c0ed661081cf size: 1362

创建 web 服务

使用 secret 认证,登录私有仓库并下载 nginx 镜像

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
      - name: myserver-myapp-frontend
        image: registry.cn-shanghai.aliyuncs.com/shichu/baseimages:nginx-1.18.0
        ports:
          - containerPort: 80
      imagePullSecrets:
        - name: aliyun-registry-image-pull-key

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend
  namespace: myserver
spec:
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30021
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-frontend

验证

下载阿里云私有仓库镜像,创建 web 服务

# 查看pod
[root@k8s-deploy yaml]#kubectl get pod -n myserver -owide
NAME                                                  READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
myserver-myapp-frontend-deployment-6559868768-t99rl   1/1     Running   0          29s   10.200.107.221   10.0.0.43   <none>           <none>

# service
root@k8s-deploy yaml]#kubectl get svc -n myserver -owide
NAME                      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE   SELECTOR
myserver-myapp-frontend   NodePort   10.100.47.93    <none>        80:30021/TCP                 45s   app=myserver-myapp-frontend

# 查看创建pod信息,下载阿里云私有仓库镜像
[root@k8s-deploy yaml]#kubectl describe pod myserver-myapp-frontend-deployment-6559868768-t99rl -n myserver
......
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  81s   default-scheduler  Successfully assigned myserver/myserver-myapp-frontend-deployment-6559868768-t99rl to 10.0.0.43
  Normal  Pulling    81s   kubelet            Pulling image "registry.cn-shanghai.aliyuncs.com/shichu/baseimages:nginx-1.18.0"
  Normal  Pulled     80s   kubelet            Successfully pulled image "registry.cn-shanghai.aliyuncs.com/shichu/baseimages:nginx-1.18.0" in 1.311082284s
  Normal  Created    80s   kubelet            Created container myserver-myapp-frontend
  Normal  Started    80s   kubelet            Started container myserver-myapp-frontend

浏览器访问,

image

  • Kubernetes

    Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。

    108 引用 • 54 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...