Kubernetes: k8s 基础篇-配置管理
- TAGS: Kubernetes
ConfigMap
云原生要素-配置分离
- Java Out of Code
- SpringCloud ConfigServer
- Apollo
- ConfigMap&Secret
什么是configmap
一般用 ConfigMap 去管理一些配置文件,或者一些大量的环境变量信息。
ConfigMap 将配置和 Pod分开,有一个nginx, nginx.conf-> configmap, nginx 去读取configmap的信息。更易于配置文件的自动更新和管理。
Secret: Secret更倾向于存储和共享敏感、加密的配置信息。
配置文档:https://kubernetes.io/docs/concepts/configuration/configmap/
yaml 文件中多行字符串
参考:
yaml 文件中多行字符串可以使用|保留换行符,或者使用>将换行符替换为空格。其中,这两个换行符有以下几种用法:
- |:文中自动换行,默认仅保留一行空行
- |+:文中自动换行,保留字符串后面所有的空行
- |-:文中自动换行,删除字符串后面所有的空行
- >:文中不自动换行,默认仅保留一行空行
- >+:文中不自动换行,保留字符串后面所有的空行
- >-:文中不自动换行,删除字符串后面所有的空行
多行字符串可以使用引号括起来:" "会进行特殊字符转义,' '保留原始字符串。
测试
import yaml with open('string.yaml','r', encoding='utf-8') as f: data = yaml.load(f, Loader=yaml.FullLoader) for key in data: print(f'{key}:{data[key]}')
string_1: | I am a string_1. 11111. string_2: |+ I am a string_2. 22222. string_3: |- I am a string_3. 33333. string_4: > I am a string_4. 44444. string_5: >+ I am a string_5. 55555. string_6: >- I am a string_6. 66666.
[root@localhost ~]# python3 read_yaml.py string_1:I am a string_1. 11111. string_2:I am a string_2. 22222. string_3:I am a string_3. 33333. string_4:I am a string_4. 44444. string_5:I am a string_5. 55555. string_6:I am a string_6. 66666. [root@localhost ~]#
范例
spec:
containers:
- name: mq-nameserver-1
image: gehuiwin/rocketmq:4.9.2
imagePullPolicy: IfNotPresent
env:
- name: JAVA_OPT_EXT
value: |-
-XX:+PerfDisableSharedMem
-Xloggc:/home/rocketmq/logs/rocketmq_gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=4 -XX:GCLogFileSize=128M
-Duser.timezone=Asia/Calcutta -Duser.home=/home/rocketmq -Xms512M -Xmx512M -Xmn512m
创建 ConfigMap 的几种形式
基于目录或文件创建 ConfigMap
–from-file 可指定单个文件和目录创建,指定目录会创建包含该目录中所有文件的configmap:
# 指定目录 kubectl create configmap *** --from-file=/path # 指定文件或多个文件 kubectl create configmap *** --from-file=file1 #其中,--from-file可以使用多次,比如: kubectl create configmap *** --from-file=file1 --from-file=file2 # 自定义 key 名称, 默认为文件名 kubectl create configmap *** --from-file=keyname=file1
范例基于目录创建 ConfigMap
准备文件
$ mkdir conf $ cat conf/game1.conf lives=3 secret.code=true $ cat conf/game2.conf color.good=purple user=tomcat
基于目录创建 ConfigMap
$ kubectl create cm cmfromdir --from-file=conf/
$ kubectl get cm cmfromdir -oyaml
apiVersion: v1
data:
game1.conf: |
lives=3
secret.code=true
game2.conf: |
color.good=purple
user=tomcat
kind: ConfigMap
metadata:
name: cmfromdir
namespace: default
创建自定义文件名称的 ConfigMap
$ kubectl create cm cmspecfile --from-file=my=conf/game2.conf $ kubectl get cm cmspecfile -oyaml apiVersion: v1 data: my: | color.good=purple user=tomcat kind: ConfigMap metadata: name: cmspecfile namespace: default
基于key-value字符串的环境变量创建 ConfigMap
常用于 Pod 的环境变量
kubectl create configmap *** --from-literal=config1=123 --from-literal=PASSWORD=234 kubectl create cm *** --from-env-file=conf/game1.conf
–from-literal 变量比较少时使用
范例 env 文件创建 ConfigMap
–from-env-file 创建
$ kubectl create cm envcm --from-env-file=conf/game1.conf $ kubectl get cm envcm -oyaml apiVersion: v1 data: lives: "3" secret.code: "true" kind: ConfigMap metadata: name: envcm namespace: default
通过 yaml / json文件创建(推荐)
这种是我比较推荐的方式,创建configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: test-conf
namespace: test
data:
test-conf: |+
SESSION_LIFETIME: 3600
URL: "http://test-server:8080"
注意:查看 ConfigMap 格式是乱码,一般为 yaml 文件内容换行前有空格,去掉即可。
使用 ConfigMap
准备 deployment 文件
kubectl create deploy dp-cm --image=nginx --dry-run=client -oyaml > dp-cm.yaml
$ cat dp-cm.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: dp-cm
name: dp-cm
spec:
replicas: 1
selector:
matchLabels:
app: dp-cm
template:
metadata:
labels:
app: dp-cm
spec:
containers:
- image: nginx
name: nginx
准备 ConfigMap 文件
$ cat app-config.yaml
apiVersion: v1
data:
TZ: Asia/Calcutta
APP_NAMESPACE: ludo-prd
APP_ENV: prod
APP_JVM_CONFIG: |-
-Dfile.encoding=utf-8
-server
-XX:+UseG1GC
-XX:+ExitOnOutOfMemoryError
-XX:InitialRAMPercentage=75.0
-XX:MinRAMPercentage=75.0
-XX:MaxRAMPercentage=75.0
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/opt/logs/
PreStop.sh: |-
#! /bin/bash
sleep 5
curl --connect-timeout 5 --max-time 5 -s -i "http://localhost:8080/admin/maintain"
sleep 40
curl --connect-timeout 5 --max-time 5 -s -i -H "Content-Type: application/json" -X POST http://localhost:8099/actuator/shutdown
sleep 60
kind: ConfigMap
metadata:
name: app-config
使用 valueFrom 定义环境变量
$ cat dp-cm.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: dp-cm
name: dp-cm
spec:
replicas: 1
selector:
matchLabels:
app: dp-cm
template:
metadata:
labels:
app: dp-cm
spec:
containers:
- env: # 定义环境变量
- name: TZ # 请注意这里可以和 ConfigMap 中的键名不一样的
valueFrom:
configMapKeyRef:
name: app-config # 这个值来自 ConfigMap
key: TZ # 需要取值的键
- name: KAFKA_TOPIC_NAME
valueFrom:
configMapKeyRef:
name: app-config
key: APP_NAMESPACE
- name: SERVICE_NAME
value: "ludo-user"
image: nginx
name: nginx
查看 Pod 环境变量
$ kubectl apply -f app-config.yaml $ kubectl apply -f dp-cm.yaml $ kubectl exec -it dp-cm-f86b8cdf-glfnt -- env |grep -iE "TZ|KAFKA" KAFKA_TOPIC_NAME=ludo-prd TZ=Asia/Calcutta
自带的变量:
# 根据 kubecet get po -ojson 查看自带的变量
- name: NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
使用 envFrom 批量生产环境变量
envFrom 将所有 ConfigMap 的数据定义为容器环境变量
$ cat dp-cm.yaml
...
spec:
containers:
- env:
- name: SERVICE_NAME
value: "ludo-user"
envFrom:
- configMapRef:
name: app-config
image: nginx
name: nginx
注意:在 linux 中变量名不能包含点 . 的
给每个环境变量名称加前缀
deploy.spec.template.spec.containers[].envFrom[].prefix
$ cat dp-cm.yaml
...
spec:
containers:
- env:
- name: SERVICE_NAME
value: "ludo-user"
envFrom:
- configMapRef:
name: app-config
prefix: "fromCm_"
image: nginx
name: nginx
以文件的形式挂载 ConfigMap
$ cat dp-cm.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: dp-cm
name: dp-cm
spec:
replicas: 1
selector:
matchLabels:
app: dp-cm
template:
metadata:
labels:
app: dp-cm
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /opt/PreStop.sh
name: app-config # volumes 中对应的名称
subPath: PreStop.sh # 取 key 对应的 value 值,文件权限511
- mountPath: /opt/a/PreStop.sh
name: test
subPath: PreStop.sh.bak
- mountPath: /opt/conf.d/
name: test # 挂载目录,目录本身文件因挂载而消失,可自动更新文件
volumes:
- configMap:
defaultMode: 0777
name: app-config
name: app-config
- configMap:
defaultMode: 0644
items: # 只使用 ConfigMap 部分的 key
- key: PreStop.sh # 指定 ConfigMap 中的 key
path: PreStop.sh # 指定挂载的名称
- key: PreStop.sh
path: PreStop.sh.bak
mode: 0755 # 指定文件权限,优先级高
name: app-config
name: test
查看
$ kubectl exec -it dp-cm-bc6f948f-qd8jr -- bash root@dp-cm-bc6f948f-qd8jr:/# ls /opt/ PreStop.sh a conf.d root@dp-cm-bc6f948f-qd8jr:/# ls /opt/a/ PreStop.sh root@dp-cm-bc6f948f-qd8jr:/# ls /opt/conf.d/ PreStop.sh PreStop.sh.bak
注意:
- 默认挂载目录,目录本身的文件因挂载而消失,同时修改 ConfigMap 可自动更新 Pod 中文件内容
- subPath 无法动态更新文件内容。
自定义挂载权限及名称
名称用法见上文 权限与 linux 中权限一致,推荐写 8 进制方式
- configMap:
defaultMode: 420 # 即 8 进制的 0644
items: # 只使用 ConfigMap 部分的 key
- key: PreStop.sh
path: PreStop.sh.bak
mode: 0755 # 指定文件权限,优先级高
defaultMode 是可选的:默认情况下,模式位用于为已创建的文件设置权限。 必须是 0000 到 0777 之间的八进制值或 0 到 511 之间的十进制值。 YAML 既接受八进制值也接受十进制值,JSON 针对模式位需要十进制值。此字段默认为 0644。
8进制与10进制互转换
root@dp-cm-5f766576cb-kjmrv:/opt/conf.d/..data# ls -l total 8 -rw-r--r-- 1 root root 251 Sep 6 17:18 PreStop.sh -rwxr-xr-x 1 root root 251 Sep 6 17:18 PreStop.sh.bak printf '%d\n' 0644 # 8 转 10 420 # printf '%o\n' 511 # 10 转 8 777
示例
挂载文件同时挂载nfs
配置configmap
apiVersion: v1
data:
APP_ENV: prod
APP_JVM_CONFIG: |-
-Dfile.encoding=utf-8
-server
-XX:+UseG1GC
-XX:+ExitOnOutOfMemoryError
-XX:InitialRAMPercentage=75.0
-XX:MinRAMPercentage=75.0
-XX:MaxRAMPercentage=75.0
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/opt/logs/
APP_NAMESPACE: default
TZ: Asia/ShangHai
postStart.sh: |-
#!/bin/bash
#set -ex
service_name=$1
[ -z ${service_name} ] && { echo "未定义service_name...退出" ; exit; }
#service_port=""
#if [ ${service_name} = "x11" ]; then
# service_port='1028'
#elif [ ${service_name} = "x12" ]; then
# service_port='1034'
#else
# service_port=""
#fi
#[ -z ${service_port} ] && { echo "未定义service_port...退出" ; exit; }
declare -A name_port
name_port=()
name_port+=([x11]='1028')
name_port+=([x12]='1029')
service_port=${name_port[${service_name}]}
APP_NAME="ROOT.jar"
CAPTURE_DIR="/tmp/debug/${HOSTNAME}-`hostname -i`/arthas_captures"
REPORT_FILE="$CAPTURE_DIR/report.txt"
monitor_health() {
while :
do
command -v curl &> /dev/null || { echo "没有curl命令,退出循环" ; break; }
val=$(curl -o /dev/null -s -w "%{http_code}" http://127.0.0.1:${service_port}/actuator/health/liveness)
echo "val-> ${val}"
if [[ $val != "200" ]];then
# 创建目录
mkdir -p $CAPTURE_DIR
echo "-----" > $REPORT_FILE
echo "----------http://127.0.0.1:${service_port}/actuator/health/liveness 非200,开始分析: $(TZ='CST-8' date +%Y%m%d_%H%M%S.%N)" |tee $REPORT_FILE
take_thread_dump |tee -a $REPORT_FILE
fi
sleep 5
done
}
take_thread_dump() {
# 获取PID
PID=$(jps -l | grep "$APP_NAME" | awk '{print $1}')
if [ -z "$PID" ]; then
echo "错误: 找不到 $APP_NAME 的进程"
echo "当前Java进程:"
jps -l
exit 1
fi
echo "=== 应用信息 ==="
echo "进程名称: $APP_NAME"
echo "进程PID: $PID"
echo "监听端口: $PORT"
# 生成唯一时间戳(纳秒级)
TIMESTAMP=$(TZ='CST-8' date +%Y%m%d_%H%M%S.%N)
echo "=== 开始抓取现场数据: $TIMESTAMP ==="
# 1. 抓取完整线程栈(最关键的)
echo "1. 抓取jstack线程栈..."
jstack -l $PID > $CAPTURE_DIR/${TIMESTAMP}_jstack_full.log 2>&1
# 2. 重点抓取XNIO/Undertow线程(根据你的线程名)
echo "2. 抓取XNIO相关线程..."
jstack -l $PID | grep -B 5 -A 25 "XNIO" > $CAPTURE_DIR/${TIMESTAMP}_jstack_xnio.log 2>&1
# 3. 抓取GC信息
echo "3. 抓取GC信息..."
jstat -gcutil $PID 1000 3 > $CAPTURE_DIR/${TIMESTAMP}_jstat_gc.log 2>&1
# 4. 抓取堆内存信息
echo "4. 抓取堆内存信息..."
jmap -heap $PID > $CAPTURE_DIR/${TIMESTAMP}_jmap_heap.log 2>&1
# 5. 网络连接信息
echo "5. 抓取网络连接..."
netstat -ant | grep ":$PORT" > $CAPTURE_DIR/${TIMESTAMP}_netstat.log 2>&1
netstat -ant | grep ESTABLISHED | wc -l > $CAPTURE_DIR/${TIMESTAMP}_established_count.log 2>&1
# 6. 系统负载
echo "6. 抓取系统信息..."
uptime > $CAPTURE_DIR/${TIMESTAMP}_system.log 2>&1
free -m >> $CAPTURE_DIR/${TIMESTAMP}_system.log 2>&1
# 7. 尝试通过Arthas抓取(如果已连接)
echo "7. 尝试通过Arthas抓取..."
if command -v arthas &> /dev/null; then
# 这里需要根据你的Arthas连接方式来调整
echo "注意: Arthas命令需要根据实际情况调整" > $CAPTURE_DIR/${TIMESTAMP}_arthas_note.txt
else
echo "Arthas未安装或不在PATH中" > $CAPTURE_DIR/${TIMESTAMP}_arthas_note.txt
fi
# 8. 生成摘要报告
echo "8. 生成摘要报告..."
{
echo "=== 现场抓取摘要 ==="
echo "时间: $(TZ='CST-8' date)"
echo "PID: $PID"
echo "应用: $APP_NAME"
echo ""
echo "=== 线程状态统计 ==="
grep "java.lang.Thread.State:" $CAPTURE_DIR/${TIMESTAMP}_jstack_full.log | sort | uniq -c
echo ""
echo "=== 活跃连接数 ==="
cat $CAPTURE_DIR/${TIMESTAMP}_established_count.log
echo ""
echo "=== 抓取的文件 ==="
ls -la $CAPTURE_DIR/${TIMESTAMP}_*
} > $CAPTURE_DIR/${TIMESTAMP}_summary.txt
echo ""
echo "=== 抓取完成 ==="
echo "数据已保存到 $CAPTURE_DIR/"
echo ""
echo "=== 关键信息摘要 ==="
tail -20 $CAPTURE_DIR/${TIMESTAMP}_summary.txt
# 提供分析建议
echo ""
echo "=== 分析建议 ==="
echo "1. 查看慢线程: grep -A 30 'XNIO-2 task' $CAPTURE_DIR/${TIMESTAMP}_jstack_full.log"
echo "2. 查看线程状态: grep 'java.lang.Thread.State:' $CAPTURE_DIR/${TIMESTAMP}_jstack_full.log | sort | uniq -c"
echo "3. 查看GC情况: cat $CAPTURE_DIR/${TIMESTAMP}_jstat_gc.log"
echo "4. 查看连接数: cat $CAPTURE_DIR/${TIMESTAMP}_established_count.log"
}
wtime=$2
[ -z $wtime ] && wtime=300 || :
echo "启动监听,预处理等待 $wtime s"
sleep $wtime
monitor_health
kind: ConfigMap
metadata:
name: app-config
namespace: default
测试POD
apiVersion: v1
kind: Pod
metadata:
name: app1
namespace: default
spec:
containers:
- name: app1
image: nginx
command: ["/bin/sh"]
args: ["-c", "while true; do echo $(date -u) >> /data/out1.txt; sleep 5; done"]
lifecycle:
postStart: # 只有 postStart 处理函数执行完毕,容器的状态才会变成 RUNNING。 不能是死循环脚本
exec:
command:
- /bin/bash
- -c
- '/opt/postStart.sh'
volumeMounts:
- mountPath: "/tmp/debug"
name: "volume-0"
readOnly: false
- mountPath: /opt/postStart.sh
name: app-config
subPath: postStart.sh
volumes:
- name: "volume-0"
nfs:
path: "/mnt/nfs/debug"
readOnly: false
server: "10.2.0.1"
- configMap:
defaultMode: 420
items:
- key: postStart.sh
path: postStart.sh
mode: 0755
name: app-config
name: app-config
deployment测试
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: x11
name: x11
namespace: default
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: x11
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: x11
spec:
containers:
- command:
- sh
- '-c'
- /opt/bin/postStart.sh x11 & /start.sh
env:
- name: LANG
value: C.UTF-8
- name: JAVA_HOME
value: /usr/local/openjdk-8
- name: JAVA_BASE_URL
value: >-
https://github.com/AdoptOpenJDK/openjdk8-upstream-binaries/releases/download/jdk8u222-b10/OpenJDK8U-jre_
- name: TZ
value: Asia/Shanghai
- name: JAVA_OPTS
value: '-Xmx1g -Xms1g'
- name: aliyun_logs_x11-stdout
value: stdout
image: >-
x.cr.xx.com/x/x11:273
imagePullPolicy: Always
lifecycle:
preStop:
exec:
command:
- sh
- '-c'
- >-
curl -X POST http://127.0.0.1:1028/actuator/eureka-registry
&& sleep 90
livenessProbe:
failureThreshold: 8
httpGet:
path: /actuator/health/liveness
port: 1028
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 3
name: x11
readinessProbe:
failureThreshold: 5
httpGet:
path: /actuator/health/readiness
port: 1028
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 3
resources:
limits:
cpu: '1'
memory: 2Gi
requests:
cpu: 100m
memory: 1Gi
volumeMounts:
- mountPath: /tmp/debug
name: volume-0
- mountPath: /opt/bin/
name: app-config
dnsPolicy: ClusterFirst
imagePullSecrets:
- name: x1-docker-hub
- name: x2-docker-hub
restartPolicy: Always
terminationGracePeriodSeconds: 100
volumes:
- name: volume-0
nfs:
path: /mnt/nfs/debug
server: 10.2.0.1
- configMap:
defaultMode: 420
items:
- key: postStart.sh
mode: 493
path: postStart.sh
name: app-config
name: app-config
Secret
什么是secret
文档:https://kubernetes.io/docs/concepts/configuration/secret/
用于存储和管理一些敏感数据,比如密码,token,密钥等敏感信息。它把 Pod 想要访问的加密数据存放到 Etcd 中。然后用户就可以通过在 Pod 的容器里挂载 Volume 的方式或者环境变量的方式访问到这些 Secret 里保存的信息了。
Secret 常用类型
- Opaque:通用型Secret,默认类型;
- kubernetes.io/service-account-token:作用于ServiceAccount,包含一个令牌,用于标识API服务账户;
- kubernetes.io/dockerconfigjson:下载私有仓库镜像使用的Secret,和宿主机的/root/.docker/config.json一致,宿主机登录后即可产生该文件;
- kubernetes.io/basic-auth:用于使用基本认证(账号密码)的Secret,可以使用Opaque取代;
- kubernetes.io/ssh-auth:用于存储ssh密钥的Secret
- kubernetes.io/tls:用于存储HTTPS域名证书文件的Secret,可以被Ingress使用;
- bootstrap.kubernetes.io/token:一种简单的 bearer token,用于创建新集群或将新节点添加到现有集群,在集群安装时可用于自动颁发集群的证书。
创建 Secret 的几种形式
- 使用 kubectl 命令来创建 Secret
- 基于配置文件来创建 Secret
- 使用 kustomize 来创建 Secret
使用 kubectl 命令创建 Secret
命令行创建时可指定的类型
- docker-registry Create a secret for use with a Docker registry
- generic Create a secret from a local file, directory or literal value
- tls Create a TLS secret
基于文件的方式创建
类似于 ConfigMap 创建
echo -n 'admin' > ./username.txt echo -n '1f2d1e2e67df' > ./password.txt kubectl create secret generic db-user-pass \ --from-file=./username.txt \ --from-file=./password.txt # 默认密钥名称是文件名。 你可以选择使用 --from-file=[key=]source 来设置密钥名称。
基于 key-value 标签提供 Secret 数据
kubectl create secret generic db-user-pass \ --from-literal=username=devuser \ --from-literal=password='S!B\*d$zDsb=' #注意,包含特殊字符(例如:$,\,*,= 和 !)由你的 shell 解释执行,而且需要转义。推荐使用单引号,而不使用双引号 ### 解码 $ kubectl get secrets db-user-pass -oyaml apiVersion: v1 data: password: UyFCXCpkJHpEc2I9 username: ZGV2dXNlcg== # echo 'UyFCXCpkJHpEc2I9' | openssl base64 -d S!B\*d$zDsb= # kubectl get secret db-user-pass -o jsonpath='{.data.password}' |base64 -d S!B\*d$zDsb=
镜像拉取凭证
kubectl create secret docker-registry myregistrykey \ --docker-server=DOCKER_REGISTRY_SERVER \ --docker-username=DOCKER_USER \ --docker-password=DOCKER_PASSWORD \ --docker-email=DOCKER_EMAIL
- docker-registry:指定Secret的类型
- myregistrykey: Secret名称
- DOCKER_REGISTRY_SERVER:镜像仓库地址
- DOCKER_USER:镜像仓库用户名,需要有拉取镜像的权限
- DOCKER_PASSWORD:镜像仓库密码
- DOCKER_EMAIL:邮箱信息,可以为空
证书
kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key
yaml 文件
基于明文方式创建
创建完后会自动加密
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
stringData:
config.yaml: |
apiUrl: "https://my.api.com/api/v1"
username: <user>
password: <password>
其它详情请查看官方文档。
使用 Secret
挂载和生成环境变量与 ConfigMap 使用方式一样,这里不重启赘述了。
使用Secret拉取私有仓库镜像
创建镜像 Secret
#kubectl create secret docker-registry docker-pull --docker-username=k8s-pull --docker-password=QpJUfm9LBv --docker-server=https://pg-ops-harbor.xxx.com -n default --- apiVersion: v1 data: .dockerconfigjson: eyIjoiY0NVRFSjIifX19 kind: Secret metadata: name: docker-pull namespace: default type: kubernetes.io/dockerconfigjson
挂载镜像凭证
pod.spec.imagePullSecrets[].namepod 中指定镜像凭证,可多个,依次请求- 基于用户访问认证
Secret管理HTTPS证书
做成自签证书
openssl genrsa -out tls.key 2048 openssl req -new -x509 -days 365 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=test.com
创建证书 Secrets
#kubectl -n default create secret tls nginx-test-tls --key=tls.key --cert=tls.crt --- apiVersion: v1 data: tls.crt: *** tls.key: *** kind: Secret metadata: name: nginx-test-tls namespace: default type: kubernetes.io/tls
使用 ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
name: example
spec:
ingressClassName: nginx
tls:
- hosts:
- nginx.test.com # SSL 证书对应的域名 (必填)。
secretName: nginx-test-tls
rules:
- host: "nginx.test.com"
http:
paths:
- backend:
service:
name: nginx
port:
number: 80
path: /
pathType: ImplementationSpecific
ConfigMap&Secret 热更新
Kubernetes中提供configmap,用来管理应用的配置,configmap具备热更新的能力,但只有通过目录挂载的configmap才具备热更新能力,其余通过环境变量,通过subPath挂载的文件都不能动态更新。
使用volume的方式挂载configmap之后,当configmap更新之后,变量的值会发生变化
但是中间会存在一定的时间间隔,大约是10左右,这主要是因为kubelet 对pod的同步间隔是10秒,另外需要注意的是当使用subpath将configmap中的某个文件单独挂载到目录下,那这个文件是无法热更新的,这是configmap本身的逻辑决定的。
热更新ConfigMap 和 Secert
# 基于文件的形式 kubectl create cm nginx-conf --from-file=nginx.conf --dry-run -oyaml | kubectl replace -f -
手动为 ServiceAccount 创建长期有效的 API 令牌
https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
从 1.29 版本开始,如果传统 ServiceAccount 令牌在一定时间段(默认设置为一年)内未被使用,则会被标记为无效。
说明:Kubernetes 在 v1.22 版本之前自动创建用来访问 Kubernetes API 的长 期凭据。 这一较老的机制是基于创建令牌 Secret 对象来实现的,Secret 对象 可被挂载到运行中的 Pod 内。 在最近的版本中,包括 Kubernetes v1.31,API 凭据可以直接使用 TokenRequest API 来获得,并使用一个投射卷挂载到 Pod 中。使用此方法获得的令牌具有受限的生命期长度,并且能够在挂载它们的 Pod 被删除时自动被废弃。
你仍然可以通过手动方式来创建服务账号令牌 Secret 对象,例如你需要一个永 远不过期的令牌时。 不过,使用 TokenRequest 子资源来获得访问 API 的令牌 的做法仍然是推荐的方式
kubectl create sa build-robot #生成临时token kubectl create token build-robot #--duration 参数来请求特定的令牌有效期 #手动为 ServiceAccount 创建长期有效的 API 令牌 kubectl apply -f - <<EOF apiVersion: v1 kind: Secret metadata: name: build-robot annotations: kubernetes.io/service-account.name: build-robot type: kubernetes.io/service-account-token EOF kubectl get secret build-robot -o jsonpath={".data.token"} | base64 -d
老方法
kubectl apply -f - <<EOF apiVersion: v1 kind: ServiceAccount metadata: name: cluster-readonly namespace: kube-system secrets: - name: cluster-readonly EOF kubectl -n kube-system get secret cluster-readonly -o jsonpath={".data.token"} | base64 -d
ConfigMap&Secret使用限制
- 提前场景ConfigMap和Secret
- 引用Key必须存在
- envFrom、valueFrom无法热更新环境变量
- envFrom配置环境变量,如果key是无效的,它会忽略掉无效的key
- ConfigMap和Secret必须要和Pod或者是引用它资源在同一个命名空间
- subPath也是无法热更新的
- ConfigMap和Secret最好不要太大
k8s1.19的不可变Secret和ConfigMap
比如秒杀系统中,设置了某个值是100,只能100个人秒杀成功,这个值不可变
kubectl create cm test-immutable --from-file=/etc/kubernetes/admin.kubeconfig # 最后加上 kubectl edit cm test-immutable immutable: true # 再去修改 kubectl edit cm test-immutable, 发现无法修改
说明: 一旦一个 Secret 或 ConfigMap 被标记为不可更改,撤销此操作或者更改 data 字段的内容都是 不 可能的。 只能删除并重新创建这个 Secret。现有的 Pod 将维持对已删除 Secret 的挂载点 – 建议重新创建这些 Pod。
解决 configmap 乱码
制表符TAB、尾随空格
Kubernetes ConfigMap在load过程中发现文件中包含tab缩进,直接转化为\n\t。
# 使用以下方法删除尾随空格,空格替换制表符 sed -i -E 's/[[:space:]]+$//g' file.txt sed -i 's/\t/ /g' file.txt
kubectl get cm my-cm -o json | jq '.data."nginx.conf"' -r # 将my-cm这个configmap资源以json格式化输出,格式化范围是/data/nginx.conf内容