阿里云ACK的etcd证书过期手工升级操作

一.问题现象

阿里云ACK的etcd证书过期,通过图形化界面升级提示升级失败,考虑通过脚本的方式升级ETCD相关的证书。由于在前期做类似的升级ETCD证书失败导致整个集群业务出现访问异常,所有在升级之前做好对应的备份操作是很有必要的

二.前期准备

1.由于升级操作是在master节点操作,涉及的证书文件变更都在master节点,所以针对阿里云ACK的3台master节点做快照。

2.针对阿里云ACK的3台master节点涉及的证书目录做备份,必要情况下备份到其他服务器上。

3.针对阿里云ACK的etcd数据库做备份操作

date;
CACERT="/var/lib/etcd/cert/ca.pem"
CERT="/var/lib/etcd/cert/etcd-server.pem"
EKY="/var/lib/etcd/cert/etcd-server-key.pem"
ENDPOINTS="172.16.0.87:2379"#etcdctl snapshot save /data/etcd_backup_dir/etcd-snapshot-`date +%Y%m%d`.dbETCDCTL_API=3 etcdctl \
--cacert="${CACERT}" --cert="${CERT}" --key="${EKY}" \
--endpoints=${ENDPOINTS} \
snapshot save /data/etcd_backup_dir/etcd-snapshot-`date +%Y%m%d`.db

备份ETCD的数据目录 

cp -r /var/lib/etcd /var/lib/etcd-`date +%Y%m%d`.bak

4.针对阿里云ACK的所有部署资源的yaml文件做备份,涉及service deploy ingress configmap secret job cronjob daemonset statefulset pvc等,备份脚本如下:

#!/bin/bash
#define variable
BACKUP_PATH=/data/k8s-backup
BACKUP_PATH_DATA=$BACKUP_PATH/yaml/`date +%Y%m%d%H%M%S`
BACKUP_PATH_LOG=$BACKUP_PATH/log
BACKUP_LOG_FILE=$BACKUP_PATH_LOG/k8s-backup-`date +%Y%m%d%H%M%S`.log
# base function
function printlog(){echo "`date +'%Y-%m-%d %H:%M:%S'` $1"echo "`date +'%Y-%m-%d %H:%M:%S'` $1" >> $BACKUP_LOG_FILE 2>&1 
}
function printlogonly(){echo "`date +'%Y-%m-%d %H:%M:%S'` $1" >> $BACKUP_LOG_FILE 2>&1 
}
# set K8s type(此处可根据集群资源自行修改)
CONFIG_TYPE="service deploy ingress configmap secret job cronjob daemonset statefulset pvc"
# make dir
mkdir -p $BACKUP_PATH_DATA
mkdir -p $BACKUP_PATH_LOG
cd $BACKUP_PATH_DATA
# set namespace list
ns_list=`kubectl get ns | awk '{print $1}' | grep -v NAME`
if [ $# -ge 1 ]; then
ns_list="$@"
fi
# define counters
COUNT_NS=0
COUNT_ITEM_IN_NS=0
COUNT_ITEM_IN_TYPE=0
COUNT_ITEM_ALL=0
# print hint
printlog "Backup kubernetes config in namespaces: ${ns_list}"
printlog "Backup kubernetes config for [type: ${CONFIG_TYPE}]."
printlog "If you want to read the record of backup, please input command ' tail -100f ${BACKUP_LOG_FILE} '"
# ask and answer
message="This will backup resources of kubernetes cluster to yaml files."
printlog ${message}ls# loop for namespaces
for ns in $ns_list;
do
COUNT_NS=`expr $COUNT_NS + 1`
printlog "Backup No.${COUNT_NS} namespace [namespace: ${ns}]."
COUNT_ITEM_IN_NS=0## loop for types
for type in $CONFIG_TYPE; 
do
printlogonly "Backup type [namespace: ${ns}, type: ${type}]."
item_list=`kubectl -n $ns get $type | awk '{print $1}' | grep -v NAME | grep -v "No "`
COUNT_ITEM_IN_TYPE=0## loop for items
for item in $item_list; 
do 
file_name=$BACKUP_PATH_DATA/${ns}_${type}_${item}.yaml
printlogonly "Backup kubernetes config yaml [namespace: ${ns}, type: ${type}, item: ${item}] to file: ${file_name}"
kubectl -n $ns get $type $item -o yaml > $file_name
COUNT_ITEM_IN_NS=`expr $COUNT_ITEM_IN_NS + 1`
COUNT_ITEM_IN_TYPE=`expr $COUNT_ITEM_IN_TYPE + 1`
COUNT_ITEM_ALL=`expr $COUNT_ITEM_ALL + 1`
printlogonly "Backup No.$COUNT_ITEM_ALL file done."
done;done;
printlogonly "Backup $COUNT_ITEM_IN_TYPE files in [namespace: ${ns}, type: ${type}]."printlog "Backup ${COUNT_ITEM_IN_NS} files done in [namespace: ${ns}]."
done;# show stats
printlog "Backup ${COUNT_ITEM_ALL} yaml files in all."
printlog "kubernetes Backup completed, all done."
exit 0

三.升级证书操作步骤

1.确认集群Master节点之间配置了root用户的免密登录。

在Master上通过SSH方式登录其他任意Master节点,如果提示输入密码,请您按如下方式配置Master节点之间的免密登录。

1. ssh-keygen -t rsa  # 生成密钥。
2. ssh-copy-id -i ~/.ssh/id_rsa.pub $(internal-ip)     # 使用ssh-copy-id工具传输公钥到其他所有Master节点,$(internal-ip)为其他Master节点的内网IP。

2.分别复制以下脚本内容,保存并命名为restart-apiserver.sh和rotate-etcd.sh,然后将两者保存到同一个文件夹下

restart-apiserver.sh

 #! /bin/bashfunction restart_apiserver() {apiserverID=$(/usr/bin/docker ps | grep kube-apiserver | grep -v NAME | awk '{print $1}')/usr/bin/docker stop $apiserverIDrm -rf /root/kube-apiserver.yamlmv /etc/kubernetes/manifests/kube-apiserver.yaml /root/kube-apiserver.yamlwhile true; doNUM=$(docker ps | grep kube-apiserver | wc -l)if [[ $NUM == 0 ]]; thenbreakfisleep 1done/usr/bin/docker ps -a | grep kube-apiserver | awk '{print $1}' | xargs docker stop/usr/bin/docker ps -a | grep kube-apiserver | awk '{print $1}' | xargs docker rmmv /root/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yamlwhile true; doNUM=$(docker ps | grep kube-apiserver | grep -v pause | wc -l)if [[ $NUM == 1 ]]; thenbreakfisleep 1donek8s::wait_apiserver_ready
}k8s::wait_apiserver_ready() {set -efor i in $(seq 180); doif kubectl get po &>/dev/null; thenreturn 0elseecho "wait apiserver to be ready, retry ${i}th after 1s"sleep 1fidoneecho "failed to wait apiserver to be ready"return 1
}function restart_container() {crictl pods | grep kube-apiserver | awk '{print $1}' | xargs -I '{}' crictl stopp {} || true
}if [[ -f /usr/bin/docker ]]; thenrestart_apiserver
elserestart_containerk8s::wait_apiserver_ready
fi
echo "API Server restarted"

 rotate-etcd.sh

#!/bin/bashset -eo pipefaildir=/tmp/etcdcert
KUBE_CERT_PATH=/etc/kubernetes/pki
ETCD_CERT_DIR=/var/lib/etcd/cert
ETCD_HOSTS=""
function get_etcdhosts() {name1=$(ls $ETCD_CERT_DIR | grep name | grep name-1.pem | sed 's/-name-1.pem//g')name2=$(ls $ETCD_CERT_DIR | grep name | grep name-2.pem | sed 's/-name-2.pem//g')name3=$(ls $ETCD_CERT_DIR | grep name | grep name-3.pem | sed 's/-name-3.pem//g')echo "hosts: " $name1 $name2 $name3#  ETCD_HOSTS=($name1 $name2 $name3)ETCD_HOSTS=$name1" "$name2" "$name3
}function gencerts() {echo "generate ssl cert ..."rm -rf $dirmkdir -p "$dir"hosts=$(echo $ETCD_HOSTS | tr -s " " ",")echo "-----generate ca"echo '{"CN":"CA","key":{"algo":"rsa","size":2048}, "ca": {"expiry": "438000h"}}' |cfssl gencert -initca - | cfssljson -bare $dir/ca -echo '{"signing":{"default":{"expiry":"438000h","usages":["signing","key encipherment","server auth","client auth"]}}}' >$dir/ca-config.jsonecho "-----generate etcdserver"export ADDRESS=$hosts,ext1.example.com,coreos1.local,coreos1export NAME=etcd-serverecho '{"CN":"'$NAME'","hosts":[""],"key":{"algo":"rsa","size":2048}}' |cfssl gencert -config=$dir/ca-config.json -ca=$dir/ca.pem -ca-key=$dir/ca-key.pem -hostname="$ADDRESS" - | cfssljson -bare $dir/$NAMEexport ADDRESS=export NAME=etcd-clientecho '{"CN":"'$NAME'","hosts":[""],"key":{"algo":"rsa","size":2048}}' |cfssl gencert -config=$dir/ca-config.json -ca=$dir/ca.pem -ca-key=$dir/ca-key.pem -hostname="$ADDRESS" - | cfssljson -bare $dir/$NAME# gen peer-caecho "-----generate peer certificates"echo '{"CN":"Peer-CA","key":{"algo":"rsa","size":2048}, "ca": {"expiry": "438000h"}}' | cfssl gencert -initca - | cfssljson -bare $dir/peer-ca -echo '{"signing":{"default":{"expiry":"438000h","usages":["signing","key encipherment","server auth","client auth"]}}}' >$dir/peer-ca-config.jsoni=0for host in $ETCD_HOSTS; do((i = i + 1))export MEMBER=${host}-name-$iecho '{"CN":"'${MEMBER}'","hosts":[""],"key":{"algo":"rsa","size":2048}}' |cfssl gencert -ca=$dir/peer-ca.pem -ca-key=$dir/peer-ca-key.pem -config=$dir/peer-ca-config.json -profile=peer \-hostname="$hosts,${MEMBER}.local,${MEMBER}" - | cfssljson -bare $dir/${MEMBER}#-hostname="$host,${MEMBER}.local,${MEMBER}" - | cfssljson -bare $dir/${MEMBER}done## backupTIMESTAMP=$(date "+%Y%m%d%H%M%S")\cp -r $ETCD_CERT_DIR $ETCD_CERT_DIR_$TIMESTAMP\cp -r $KUBE_CERT_PATH/etcd $KUBE_CERT_PATH/etcd_$TIMESTAMP# 制作bundle cacat $KUBE_CERT_PATH/etcd/ca.pem >>$dir/bundle_ca.pemcat $ETCD_CERT_DIR/ca.pem >>$dir/bundle_ca.pemcat $dir/ca.pem >>$dir/bundle_ca.pem# 制作bundle peer-cacat $ETCD_CERT_DIR/peer-ca.pem >$dir/bundle_peer-ca.pemcat $dir/peer-ca.pem >>$dir/bundle_peer-ca.pem# chownchown -R etcd:etcd $dirchmod 0644 $dir/*
}function rotate_etcd_ca() {# Update certs on etcd nodes.for ADDR in $ETCD_HOSTS; doTIMESTAMP=$(date "+%Y%m%d%H%M%S")ssh -o StrictHostKeyChecking=no root@$ADDR cp -r $ETCD_CERT_DIR $ETCD_CERT_DIR_$TIMESTAMPecho "update etcd CA on node $ADDR"scp -o StrictHostKeyChecking=no $dir/bundle_ca.pem root@$ADDR:$ETCD_CERT_DIR/ca.pemscp -o StrictHostKeyChecking=no $dir/bundle_ca.pem root@$ADDR:$KUBE_CERT_PATH/etcd/ca.pemscp -o StrictHostKeyChecking=no $dir/etcd-client.pem root@$ADDR:$KUBE_CERT_PATH/etcd/etcd-client.pemscp -o StrictHostKeyChecking=no $dir/etcd-client-key.pem root@$ADDR:$KUBE_CERT_PATH/etcd/etcd-client-key.pemscp -o StrictHostKeyChecking=no $dir/bundle_peer-ca.pem root@$ADDR:$ETCD_CERT_DIR/peer-ca.pemssh -o StrictHostKeyChecking=no root@$ADDR chown -R etcd:etcd $ETCD_CERT_DIRssh -o StrictHostKeyChecking=no root@$ADDR chmod 0644 $ETCD_CERT_DIR/*echo "restart etcd on node $ADDR"ssh -o StrictHostKeyChecking=no root@$ADDR systemctl restart etcdecho "etcd on node $ADDR restarted"ssh -o StrictHostKeyChecking=no root@$ADDR /usr/bin/bash /tmp/restart-apiserver.shecho "apiserver on node $ADDR restarted"sleep 10done
}function rotate_etcd_certs() {for ADDR in $ETCD_HOSTS; doecho "update etcd peer certs on node $ADDR"scp -o StrictHostKeyChecking=no \$dir/{peer-ca-key.pem,etcd-server.pem,etcd-server-key.pem,etcd-client.pem,etcd-client-key.pem,ca-key.pem,*-name*.pem} root@$ADDR:$ETCD_CERT_DIR/ssh -o StrictHostKeyChecking=no root@$ADDR chown -R etcd:etcd $ETCD_CERT_DIRssh -o StrictHostKeyChecking=no root@$ADDR \chmod 0400 $ETCD_CERT_DIR/{peer-ca-key.pem,etcd-server.pem,etcd-server-key.pem,etcd-client.pem,etcd-client-key.pem,ca-key.pem,*-name*.pem}echo "restart etcd on node $ADDR"ssh -o StrictHostKeyChecking=no root@$ADDR systemctl restart etcdecho "etcd on node $ADDR restarted"sleep 10done
}function recover_etcd_ca() {# Update certs on etcd nodes.for ADDR in $ETCD_HOSTS; doecho "replace etcd CA on node $ADDR"scp -o StrictHostKeyChecking=no $dir/ca.pem root@$ADDR:$ETCD_CERT_DIR/ca.pemscp -o StrictHostKeyChecking=no $dir/ca.pem root@$ADDR:$KUBE_CERT_PATH/etcd/ca.pemscp -o StrictHostKeyChecking=no $dir/peer-ca.pem root@$ADDR:$ETCD_CERT_DIR/peer-ca.pemscp -o StrictHostKeyChecking=no $dir/ca.pem root@$ADDR:$KUBE_CERT_PATH/etcd/ca.pemssh -o StrictHostKeyChecking=no root@$ADDR chown -R etcd:etcd $ETCD_CERT_DIRecho "restart apiserver on node $ADDR"ssh -o StrictHostKeyChecking=no root@$ADDR bash /tmp/restart-apiserver.shecho "apiserver on node $ADDR restarted"echo "restart etcd on node $ADDR"sleep 5ssh -o StrictHostKeyChecking=no root@$ADDR systemctl restart etcdecho "etcd on node $ADDR restarted"sleep 5done
}function renew_k8s_certs() {# 更新K8s证书,根据集群Region替换下面cn-hangzhou的默认镜像地域。for ADDR in $ETCD_HOSTS; doecho "renew k8s components cert on node $ADDR"#compatible containerdset +essh -o StrictHostKeyChecking=no root@$ADDR docker run --privileged=true  -v /:/alicoud-k8s-host --pid host --net host \registry.cn-hangzhou.aliyuncs.com/acs/etcd-rotate:v2.0.0 /renew/upgrade-k8s.sh --role masterssh -o StrictHostKeyChecking=no root@$ADDR ctr image pull registry.cn-hangzhou.aliyuncs.com/acs/etcd-rotate:v2.0.0ssh -o StrictHostKeyChecking=no root@$ADDR ctr run --privileged=true --mount type=bind,src=/,dst=/alicoud-k8s-host,options=rbind:rw \--net-host registry.cn-hangzhou.aliyuncs.com/acs/etcd-rotate:v2.0.0 cert-rotate /renew/upgrade-k8s.sh --role masterset -eecho "finished renew k8s components cert on $ADDR"sleep 5done
}function generate_cm() {echo "generate status configmap"cat <<-"EOF" > /tmp/ack-rotate-etcd-ca-cm.yaml.tpl
apiVersion: v1
kind: ConfigMap
metadata:name: ack-rotate-etcd-statusnamespace: kube-system
data:status: "success"hosts: "$hosts"
EOFsed -e "s#\$hosts#$ETCD_HOSTS#" /tmp/ack-rotate-etcd-ca-cm.yaml.tpl | kubectl apply -f -
}get_etcdhosts
echo "${ETCD_HOSTS[@]}"echo "---renew k8s components certs---"
renew_k8s_certs
echo "---end to renew k8s components certs---"# Update certs on etcd nodes.
for ADDR in $ETCD_HOSTS; doscp -o StrictHostKeyChecking=no restart-apiserver.sh root@$ADDR:/tmp/restart-apiserver.shssh -o StrictHostKeyChecking=no root@$ADDR chmod +x /tmp/restart-apiserver.sh
donegencerts
echo "---rotate etcd ca and etcd client ca---"
rotate_etcd_ca
echo "---end to rotate etcd ca and etcd client ca---"
echo
echo "---rotate etcd peer and certs---"
rotate_etcd_certs
echo "---end to rotate etcd peer and certs---"echo
echo "---replace etcd ca---"
recover_etcd_ca
echo "---end to replace etcd ca---"generate_cm
echo "etcd CA and certs have succesfully rotated!"

提前下载镜像文件 registry.cn-hangzhou.aliyuncs.com/acs/etcd-rotate:v2.0.0

镜像里面的/renew/upgrade-k8s.sh

#!/bin/sh
set -xeif [ -d "/alicoud-k8s-host" ]; thenrm -rf /alicoud-k8s-host/usr/local/k8s-upgrademkdir -p /alicoud-k8s-host/usr/local/k8s-upgradecp -r /renew/* /alicoud-k8s-host/usr/local/k8s-upgradels -l /alicoud-k8s-host/usr/local/k8s-upgradechmod  -R +x /alicoud-k8s-host/usr/local/k8s-upgrade/chroot /alicoud-k8s-host /usr/local/k8s-upgrade/rotate.sh "$@"
fi

rotate.sh

#!/bin/sh
set -xeif [ -d "/alicoud-k8s-host" ]; thenrm -rf /alicoud-k8s-host/usr/local/k8s-upgrademkdir -p /alicoud-k8s-host/usr/local/k8s-upgradecp -r /renew/* /alicoud-k8s-host/usr/local/k8s-upgradels -l /alicoud-k8s-host/usr/local/k8s-upgradechmod  -R +x /alicoud-k8s-host/usr/local/k8s-upgrade/chroot /alicoud-k8s-host /usr/local/k8s-upgrade/rotate.sh "$@"
fi[root@master01 ~]# docker run -it registry.cn-hangzhou.aliyuncs.com/acs/etcd-rotate:v2.0.0 cat /renew/rotate.sh
#!/usr/bin/env bashset -e -xpublic::common::log() {echo $(date +"[%Y%m%d %H:%M:%S]: ") $1
}function retry() {local n=0local try=$1local cmd="${@:2}"[[ $# -le 1 ]] && {echo "Usage $0 <retry_number> <Command>"}set +euntil[[ $n -ge $try ]]do$cmd && break || {echo "Command Fail.."((n++))echo "retry $n :: [$cmd]"sleep 2}doneset -e
}public::upgrade::backupmaster() {local backup_dir=/etc/kubeadm/backup-rotate-$(date +%F)if [ ! -f $backup_dir/kubelet.conf ]; thenmkdir -p $backup_dir $backup_dir/kubelet $backup_dir/etcdcp -rf /etc/kubernetes/ $backup_dir/cp /etc/kubeadm/kubeadm.cfg $backup_dir/cp /etc/systemd/system/kubelet.service.d/10-kubeadm.conf $backup_dircp /etc/kubernetes/kubelet.conf $backup_dircp -rf /var/lib/kubelet/pki/* $backup_dir/kubeletcp -rf /var/lib/etcd/cert/* $backup_dir/etcdelsepublic::common::log "master configuration is already backup, skip."fi
}public::upgrade::backupnode() {public::common::log "Begin the node backup working."local backup_dir=/etc/kubeadm/backup-rotate-$(date +%F)if [ ! -f $backup_dir/10-kubeadm.conf ]; thenmkdir -p $backup_dir $backup_dir/kubeletcp -rf /etc/kubernetes/ $backup_dir/cp /etc/kubernetes/kubelet.conf $backup_dircp /etc/systemd/system/kubelet.service.d/10-kubeadm.conf $backup_dircp -rf /var/lib/kubelet/pki/* $backup_dir/kubeletelsepublic::common::log "node configuration is already backup, skip."fi
}public::main::master-rotate() {ls -l /usr/localpwdlocal backup_dir=/etc/kubeadm/backup-rotate-$(date +%F)echo "mode is $MODE"if ! grep "rotate-certificates" /etc/systemd/system/kubelet.service.d/10-kubeadm.conf; then./usr/local/k8s-upgrade/cert-rotate -mode=$MODE -role=master -nodeip=$NODE_IP -auto-rotate=false >$backup_dir/renew.logelse./usr/local/k8s-upgrade/cert-rotate -mode=$MODE -role=master -nodeip=$NODE_IP >$backup_dir/renew.logfiif [[ "$MODE" = "etcd" ]]; thenpublic::common::log "Successful update cert on $(hostname)"exit 0fisleep 1#renew the dashboard certsif [ -d /etc/kubernetes/pki/dashboard ]; thencp -rf /etc/kubernetes/pki/apiserver.crt /etc/kubernetes/pki/dashboard/dashboard.crtcp -rf /etc/kubernetes/pki/apiserver.key /etc/kubernetes/pki/dashboard/dashboard.keycp -rf /etc/kubernetes/pki/ca.crt /etc/kubernetes/pki/dashboard/dashboard-ca.crtcat /etc/kubernetes/pki/client-ca.crt >>/etc/kubernetes/pki/dashboard/dashboard-ca.crtif [ -f /etc/kubernetes/pki/user-ca.crt ]; thencat /etc/kubernetes/pki/user-ca.crt >>/etc/kubernetes/pki/dashboard/dashboard-ca.crtficp -rf /etc/kubernetes/pki/dashboard/dashboard-ca.crt /etc/kubernetes/pki/apiserver-ca.crtelsecp -rf /etc/kubernetes/pki/ca.crt /etc/kubernetes/pki/apiserver-ca.crtcat /etc/kubernetes/pki/client-ca.crt >>/etc/kubernetes/pki/apiserver-ca.crtif [ -f /etc/kubernetes/pki/user-ca.crt ]; thencat /etc/kubernetes/pki/user-ca.crt >>/etc/kubernetes/pki/apiserver-ca.crtfifi# /etc/kubernetes/manifests pod can not be pull up automatically. use this to workaround.set +edocker ps | grep kube-controller-manager | awk '{print $1}' | xargs -I '{}' docker restart {} || truecrictl pods | grep kube-controller-manager | awk '{print $1}' | xargs -I '{}' crictl stopp {} || trueset -esleep 1#restart kubeletservice kubelet restartsleep 1# /etc/kubernetes/manifests pod can not be pull up automatically. use this to workaround.set +edocker ps | grep kube-apiserver | awk '{print $1}' | xargs -I '{}' docker restart {} || truecrictl pods | grep kube-apiserver | awk '{print $1}' | xargs -I '{}' crictl stopp {} || truesleep 1docker ps | grep kube-scheduler | awk '{print $1}' | xargs -I '{}' docker restart {} || truecrictl pods | grep kube-scheduler | awk '{print $1}' | xargs -I '{}' crictl stopp {} || trueset -epublic::common::log "Successful update cert on $(hostname)"
}public::main::node-rotate() {if [ -f /etc/kubernetes/pki/apiserver.crt ]; thenpublic::common::log "Skip node rotate on master node"exit 0filocal backup_dir=/etc/kubeadm/backup-rotate-$(date +%F)if ! grep "rotate-certificates" /etc/systemd/system/kubelet.service.d/10-kubeadm.conf; then./usr/local/k8s-upgrade/cert-rotate -mode=$MODE -role=worker -auto-rotate=false -key=$KEY >$backup_dir/renew.logelse./usr/local/k8s-upgrade/cert-rotate -mode=$MODE -role=worker -key=$KEY >$backup_dir/renew.logfisleep 1#restart kubeletservice kubelet restartsleep 1public::common::log "Successful update cert on $(hostname)"
}public::main::master() {public::upgrade::backupmasterpublic::main::master-rotate
}public::main::node() {public::upgrade::backupnodepublic::main::node-rotate
}main() {#use renew mode in defaultexport MODE=renewwhile[[ $# -gt 0 ]]dokey="$1"case $key in--role)export ROLE=$2shift;;--mode)export MODE=$2shift;;--nodeip)export NODE_IP=$2shift;;--rootkey)export KEY=$2shift;;*)public::common::log "unkonw option [$key]"exit 1;;esacshiftdonemkdir -p /etc/kubeadm/backup-rotate-$(date +%F)#public::upgrade::backup######################################################case $ROLE in"source")public::common::log "source scripts";;"master")public::main::master;;"node")public::main::node;;*)echo "Usage:$0 --role master|node --mode renew|rotate./rotate.sh";;esac
}main "$@"

 

3.在任意Master节点上运行bash rotate-etcd.sh

当看到命令行输出etcd CA and certs have succesfully rotated!时,表示所有Master节点上的证书和K8s证书已经轮转完成。

脚本执行过程中,会将etcd相关的服务端和客户端证书备份在如下目录中:

  • /var/lib/etcd/cert_$时间戳后缀

  • /etc/kubernetes/pki/etcd_$时间戳后缀

4.查看证书有效期

openssl x509 -in cert.crt -noout -dates

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/7169.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Kubernetes运维篇】ingress-nginx实现业务灰度发布详解

文章目录 一、理论&#xff1a;实现灰度发布的几种场景1、场景一&#xff1a;将新版本灰度给部分用户2、场景二&#xff1a;按照比例流程给新版本3、实现灰度发布字段解释 二、实践&#xff1a;1、实验前提环境2、基于Request Header(请求头)进行流量分割3、基于Cookie进行流量…

93.qt qml-自定义Table优化(新增:水平拖拽/缩放自适应/选择使能/自定义委托)

之前我们更新了90.qt qml-Table表格组件(支持表头表尾固定/自定义颜色/自定义操作按钮/排序)_qml 表格_诺谦的博客-CSDN博客 但是一直没出源码,是因为该demo还存在问题,那就是表头表尾固定下,如果是半透明状态下,会看到表头表尾固定后的内容,所以只能重构代码,不能使用重…

Vue3组合式API+TypeScript写法入门

文章目录 前言1.reactive2.ref3.props4.computed5.emit6.watch总结 前言 参考Vue3官网. 本篇以组合式API为例, 但不包含setup语法糖式写法. 原本打算结合class-component, Vue3不推荐就不用了: OverView|Vue Class Component. 而且是不再推荐基于类的组件写法, 推荐单文件组件…

Android App 持续集成性能测试:启动流量

目录 前言&#xff1a; get app UID 获取流量数据 获得启动流量数据 总结 前言&#xff1a; Jenkins 是一种开源的持续集成工具&#xff0c;可以帮助我们更加方便地进行软件开发和测试工作。通过 API 远程管理 Jenkins 可以帮助我们更加方便地进行 Jenkins 的配置和管理工…

react实现路由跳转动画

下载插件 npm i react-transition-group 配置路由 import { createBrowserRouter as ReactRouter,Navigate } from "react-router-dom";import App from ../App.js import Login from "../view/login.js"; import Home from "../home.js"; co…

了解 3DS MAX 3D摄像机跟踪设置:第 4 部分

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 项目设置 步骤 1 打开“后效”。 打开后效果 步骤 2 转到合成>新合成以创建新合成。 将“宽度”和“高度”值分别设置为 1280 和 720。将帧速率设置为 25&#xff0c;将持续时间设置为 12 秒。单…

Go基本数据类型及内置函数(一文稳定基础)

文章目录 1. 基础数据类型2.内置函数3.函数4.列表操作及for循环5.原子性操作6.通道7.协程与并发安全8.定时器 1. 基础数据类型 1. bool&#xff1a;布尔类型&#xff0c;只有 true 和 false 两个值。var test2 bool true2. string&#xff1a;字符串类型&#xff0c;表示一组字…

微服务网关

1.网关是如何演化来的&#xff0c;在微服务中有什么作用&#xff1f; 随着单体架构转化为微服务架构的时候&#xff0c;由一个后台服务由一个单一的服务变成了多个微服务&#xff0c;前端应用需要调用多个服务的接口&#xff0c;为了解决这个问题&#xff0c;网关就产生了。网…

【LeetCode】55.跳跃游戏

题目 给定一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标。 示例 1&#xff1a; 输入&#xff1a;nums [2,3,1,1,4] 输出&#xff1a;true 解释&#xff1a;可以…

一个月学通Python(二十六):Django使用缓存

专栏介绍 结合自身经验和内部资料总结的Python教程,每天3-5章,最短1个月就能全方位的完成Python的学习并进行实战开发,学完了定能成为大佬!加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础)》 文章目录 专栏介绍使用缓存Django项目接入Redis为视图提供缓…

Flask 文件上传,删除上传的文件

目录结构 app.py from flask import Flask, request, render_template, redirect, url_for import osapp Flask(__name__) BASE_DIR os.getcwd() UPLOAD_FOLDER os.path.join(BASE_DIR, testfile)app.route(/) def home():files os.listdir(UPLOAD_FOLDER)return render_t…

欧盟新规,燃油噩梦?2025年起,高速公路每60公里设立一处快充站

根据外媒The Verge报道&#xff0c;欧洲电动汽车用户将获得更多便捷的待遇&#xff0c;同时还能减少有害温室气体排放&#xff0c;这得益于欧盟理事会最新通过的法规。 根据欧盟的法规要求&#xff0c;自2025年起&#xff0c;TEN-T高速公路系统在欧洲将需要每隔60公里设立一座高…

Langchain 和 Chroma 的集成

Langchain 和 Chroma 的集成 1. Chroma2. 基本示例​3. 基本示例(包括保存到磁盘)4. 将 Chroma Client 传递到 Langchain ​5. 基本示例(使用 Docker 容器)6. 更新和删除7. 带分数的相似性搜索​ 1. Chroma Chroma 是一个人工智能原生开源矢量数据库&#xff0c;专注于开发人员…

ES6基础知识六:你是怎么理解ES6中 Promise的?使用场景?

一、介绍 Promise&#xff0c;译为承诺&#xff0c;是异步编程的一种解决方案&#xff0c;比传统的解决方案&#xff08;回调函数&#xff09;更加合理和更加强大 在以往我们如果处理多层异步操作&#xff0c;我们往往会像下面那样编写我们的代码 doSomething(function(resu…

[ 容器 ] Harbor 私有仓库的部署与管理

目录 一、什么是Harbor二、Harbor的特性三、Harbor的构成四、Harbor 部署五、关于 Harbor.cfg 配置文件中有两类参数&#xff1a;所需参数和可选参数六、维护管理Harbor 一、什么是Harbor Harbor 是 VMware 公司开源的企业级 Docker Registry 项目&#xff0c;其目标是帮助用户…

jQuery的DOM操作之笔记总结

jQuery的DOM操作之笔记总结 首先我们来介绍一下什么是DOM 简述&#xff1a; 1.DOM全称Document Object Model&#xff08;文档对象模型&#xff09;。 2.每个文档都是一棵DOM结构的树&#xff0c;文档里的很多元素&#xff0c;就像树上的很多节点&#xff0c;或是分叉的树枝…

知识库数据导出为excel-使用JavaScript实现在浏览器中导出Excel文件

我们智能客服知识库机器人已经开发完成&#xff0c;后端数据库是使用的qdrant向量数据库&#xff0c;但是该数据库并没有导出备份功能&#xff0c;所以我按简单的纯前端实现知识库导出excel数据 使用第三方库(如SheetJS) SheetJS是一个流行的JavaScript库&#xff0c;可帮助处理…

腾讯云 Cloud Studio 实战训练营——快速构建React完成点餐H5页面

目录 ​编辑 一、前言 1、什么是腾讯云 Cloud Studio 2、本文实验介绍 二、前期准备工作 1、注册 Cloud Studio 2、初始化工作空间 三、开发一个简版的点餐系统页面 1、安装依赖 1.1、安装 antd-mobile 1.2、安装 less 和 less-loader 1.3、暴露 webpack 配置文件 …

OpenCV实现照片换底色处理

目录 1.导言 2.引言 3.代码分析 4.优化改进 5.总结 1.导言 在图像处理领域&#xff0c;OpenCV是一款强大而广泛应用的开源库&#xff0c;能够提供丰富的图像处理和计算机视觉功能。本篇博客将介绍如何利用Qt 编辑器调用OpenCV库对照片进行换底色处理&#xff0c;实现更加…

Stable Diffusion生成艺术二维码

Stable Diffusion生成艺术二维码 文章会有浏览问题&#xff0c;点击此处查看原文 首先需要一个Stable Diffusion服务环境&#xff0c;《Stable Diffusion服务环境搭建&#xff08;远程服务版&#xff09;》如果你已经有了那就忽略 一、准备一个比较好的二维码底图 首先解析二…