一、实现基于 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 备份流程
- Velero 客户端调用 kubernetes API Server 创建 Backup 任务
- Backup 控制器基于 watch 机制通过 API Server 获取备份任务
- Backup 控制器开始执行备份动作,其会通过请求 API Server 获取需要备份的数据
- Backup 控制器将获取到的数据备份到指定的对象存储 server 端
准备存储环境
1. 部署 minio
位部署服务器(10.0.0.8)
-
安装 docker
-
部署 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
- 进入管理页面
- 创建 bucket
- 验证 bucket
部署 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
查看备份
备份指定资源对象
#备份指定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 的nginx
Docker Hub 镜像。 - 创建一个容器并使用
.spec.template.spec.containers[0].name
字段将其命名为nginx
。 - 打开端口 80 以供 Pod 使用。
-
- 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
- 检查 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>
- 要查看指定历史版本的详细信息
[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>
回滚到之前的版本
- 回滚到历史版本
- 回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment
- 回滚到指定版本
使用 --to-revision
回滚到指定版本(如版本 5)
kubectl rollout undo deployment/nginx-deployment --to-revision=5
- 检查回滚是否成功以及 Deployment 是否正在运行
[root@k8s-deploy yaml]#kubectl get deployment nginx-deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 7h56m
- 查看 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 为例:
- 获取 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
- 暂停 deployment 上线
kubectl rollout pause deploy/nginx-deployment
- 查看历史更新记录
[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>
- 更新 deployment 镜像
kubectl set image deploy/nginx-deployment nginx=nginx:1.16.0
- 查看历史更新记录
没有新的上线被触发
[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>
- 获取上线状态验证现有的 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 上线被暂停期间不会产生任何效果。
- 恢复 deployment 上线
kubectl rollout resume deploy/nginx-deployment
- 查看上线过程
[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
- 查看完成状态
[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 的 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 工作流程
定义 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 地址下公开多个服务。
其中绿色的代表从外向内的访问模式;蓝色的代表从内向外的访问模式,黄色代表集群内部的访问模式。可以看到,除了 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。
创建 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
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 中的容器:
- 在容器命令和参数内
- 容器的环境变量
- 在只读卷里面添加一个文件,让应用来读取
- 编写代码在 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 会加密存储,所以适用于存储敏感信息。
应用场景:
- 作为挂载到一个或多个容器上的卷 中的文件。
- 作为容器的环境变量。
- 由 kubelet 在为 Pod 拉取镜像时使用。
注意:
- Secret 对象的名称必须是合法的 DNS 子域名。
- 在为创建 Secret 编写配置文件时,可以设置
data
与/或stringData
字段。data
和stringData
字段都是可选的。data
字段中所有键值都必须是 base64 编码的字符串。如果不希望执行这种 base64 字符串的转换操作,可以选择设置stringData
字段,其中可以使用任何字符串作为其取值。 data
和stringData
中的键名只能包含字母、数字、-
、_
或.
字符。stringData
字段中的所有键值对都会在内部被合并到data
字段中。 如果某个主键同时出现在data
和stringData
字段中,stringData
所指定的键值具有高优先级。
secret 挂载流程
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
卷中的数据也会被永久删除。
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
配置负载均衡
#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
- 浏览器访问 http://www.mysite.com,自动跳转 https
- 查看自签名证书
- 进入首页
私有仓库认证
创建 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
浏览器访问,
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于