krane是一个命令行工具,它可以帮助你向Kubernetes命名空间发送更改并了解结果。
为什么不直接使用标准的kubectl apply
进行部署?Krane在引擎盖下使用了它。然而,kubectl apply
却给用户留下了一些棘手的问题。刚刚发生了什么?它成功了吗?
特别是在CI/CD环境中,我们需要对每次部署有一个明确的、可操作的成功/失败的结果。提供这一点是krane的基本目标,它已经发展到支持以下核心功能。
观察你要求的变化,确保它们成功推出。
⁉️ 为失败的修改提供调试信息。
预先部署某些类型的资源(例如 ConfigMap、PersistentVolumeClaim),以确保在部署可能消费它们的资源(例如 Deployment)时,最新版本可用。
从加密的EJSON中创建Kubernetes秘密,你可以安全地提交到你的存储库。
在部署开始时使用bare pods
运行任务(使用案例:Rails迁移)。
如果你需要在部署前渲染模板中的动态值,你可以使用krane render
。与此同时,这个 repo 还包括运行任务和重启部署的工具。
https://github.com/Shopify/krane
先安装ruby,ruby-devel,gcc-c++,
sudo dnf install -y ruby ruby-devel gcc-c++
然后安装krane,
sudo gem install krane
请将CONTEXT修改为你使用的kubernetes context,
kubectl create namespace demo
NAMESPACE=demo
CONTEXT=k8s-admin@local
发布一个 deployment,
cat << EOF | krane deploy $NAMESPACE $CONTEXT -f -
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.14.2
ports:
- containerPort: 80
EOF
示例1输出日志,
[INFO][2023-01-30 10:48:03 +0800]
[INFO][2023-01-30 10:48:03 +0800] ------------------------------------Phase 1: Initializing deploy------------------------------------
[INFO][2023-01-30 10:48:03 +0800] All required parameters and files are present
[INFO][2023-01-30 10:48:03 +0800] Discovering resources:
[INFO][2023-01-30 10:48:03 +0800] - Deployment/nginx-deployment
[INFO][2023-01-30 10:48:07 +0800]
[INFO][2023-01-30 10:48:07 +0800] ----------------------------Phase 2: Checking initial resource statuses-----------------------------
[INFO][2023-01-30 10:48:07 +0800] Deployment/nginx-deployment Not Found
[INFO][2023-01-30 10:48:07 +0800]
[INFO][2023-01-30 10:48:07 +0800] ----------------------------------Phase 3: Deploying all resources----------------------------------
[INFO][2023-01-30 10:48:07 +0800] Deploying Deployment/nginx-deployment (timeout: 420s)
[INFO][2023-01-30 10:48:11 +0800] Successfully deployed in 3.6s: Deployment/nginx-deployment
[INFO][2023-01-30 10:48:11 +0800]
[INFO][2023-01-30 10:48:11 +0800] ------------------------------------------Result: SUCCESS-------------------------------------------
[INFO][2023-01-30 10:48:11 +0800] Successfully deployed 1 resource
[INFO][2023-01-30 10:48:11 +0800]
[INFO][2023-01-30 10:48:11 +0800] Successful resources
[INFO][2023-01-30 10:48:11 +0800] Deployment/nginx-deployment 3 replicas, 3 updatedReplicas, 3 availableReplicas
发布一个 non-namespaced 资源,
cat << EOF | krane global-deploy $CONTEXT -f - --selector app=krane
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: testing-storage-class
labels:
app: krane
provisioner: kubernetes.io/no-provisioner
EOF
示例2输出日志,
[INFO][2023-01-30 10:54:38 +0800]
[INFO][2023-01-30 10:54:38 +0800] ------------------------------------Phase 1: Initializing deploy------------------------------------
[INFO][2023-01-30 10:54:38 +0800] Using resource selector app=krane
[INFO][2023-01-30 10:54:38 +0800] All required parameters and files are present
[INFO][2023-01-30 10:54:38 +0800] Discovering resources:
[INFO][2023-01-30 10:54:39 +0800] - StorageClass/testing-storage-class
[INFO][2023-01-30 10:54:39 +0800]
[INFO][2023-01-30 10:54:39 +0800] ----------------------------Phase 2: Checking initial resource statuses-----------------------------
[INFO][2023-01-30 10:54:39 +0800] StorageClass/testing-storage-class Not Found
[INFO][2023-01-30 10:54:39 +0800]
[INFO][2023-01-30 10:54:39 +0800] ----------------------------------Phase 3: Deploying all resources----------------------------------
[INFO][2023-01-30 10:54:39 +0800] Deploying StorageClass/testing-storage-class (timeout: 300s)
[WARN][2023-01-30 10:54:41 +0800] Don't know how to monitor resources of type StorageClass. Assuming StorageClass/testing-storage-class deployed successfully.
[INFO][2023-01-30 10:54:41 +0800] Successfully deployed in 1.6s: StorageClass/testing-storage-class
[INFO][2023-01-30 10:54:41 +0800]
[INFO][2023-01-30 10:54:41 +0800] ------------------------------------------Result: SUCCESS-------------------------------------------
[INFO][2023-01-30 10:54:41 +0800] Successfully deployed 1 resource
[INFO][2023-01-30 10:54:41 +0800]
[INFO][2023-01-30 10:54:41 +0800] Successful resources
[INFO][2023-01-30 10:54:41 +0800] StorageClass/testing-storage-class Exists
重启1个 deployment,
krane restart $NAMESPACE $CONTEXT --deployments=nginx-deployment
示例3输入日志,
[INFO][2023-01-30 10:57:15 +0800]
[INFO][2023-01-30 10:57:15 +0800] -----------------------------------Phase 1: Initializing restart------------------------------------
[INFO][2023-01-30 10:57:15 +0800] Configured to restart deployments by name: nginx-deployment
[INFO][2023-01-30 10:57:15 +0800]
[INFO][2023-01-30 10:57:15 +0800] ------------------------------------Phase 2: Triggering restart-------------------------------------
[INFO][2023-01-30 10:57:15 +0800] Triggered `Deployment/nginx-deployment` restart
[INFO][2023-01-30 10:57:15 +0800]
[INFO][2023-01-30 10:57:15 +0800] ------------------------------------Phase 3: Waiting for rollout------------------------------------
[INFO][2023-01-30 10:57:19 +0800] Successfully restarted in 3.0s: Deployment/nginx-deployment
[INFO][2023-01-30 10:57:19 +0800]
[INFO][2023-01-30 10:57:19 +0800] ------------------------------------------Result: SUCCESS-------------------------------------------
[INFO][2023-01-30 10:57:19 +0800] Successfully restarted 1 resource
[INFO][2023-01-30 10:57:19 +0800]
[INFO][2023-01-30 10:57:19 +0800] Successful resources
[INFO][2023-01-30 10:57:19 +0800] Deployment/nginx-deployment 3 replicas, 3 updatedReplicas, 3 availableReplicas
krane run
是一个用于触发一次性工作的工具,
先部署一个PodTemplate,
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-configmap-data
labels:
name: demo-configmap-data
app: demo
data:
datapoint1: value1
datapoint2: value2
---
apiVersion: v1
kind: PodTemplate
metadata:
name: demo-pod-template-runner
labels:
name: demo-pod-template-runner
app: demo
template:
metadata:
name: task-runner
labels:
name: runner
app: demo
spec:
restartPolicy: Never
containers:
- name: task-runner
image: busybox
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "echo 'Hello from the command runner!' && test 1 -eq 1"]
env:
- name: CONFIG
valueFrom:
configMapKeyRef:
name: demo-configmap-data
key: datapoint1
EOF
输出日志,
[INFO][2023-01-30 11:04:00 +0800]
[INFO][2023-01-30 11:04:00 +0800] ------------------------------------Phase 1: Initializing deploy------------------------------------
[INFO][2023-01-30 11:04:00 +0800] All required parameters and files are present
[INFO][2023-01-30 11:04:00 +0800] Discovering resources:
[INFO][2023-01-30 11:04:01 +0800] - ConfigMap/demo-configmap-data
[INFO][2023-01-30 11:04:01 +0800] - PodTemplate/demo-pod-template-runner
[INFO][2023-01-30 11:04:05 +0800]
[INFO][2023-01-30 11:04:05 +0800] ----------------------------Phase 2: Checking initial resource statuses-----------------------------
[INFO][2023-01-30 11:04:05 +0800] ConfigMap/demo-configmap-data Available
[INFO][2023-01-30 11:04:05 +0800] PodTemplate/demo-pod-template-runner Not Found
[INFO][2023-01-30 11:04:05 +0800]
[INFO][2023-01-30 11:04:05 +0800] ------------------------------Phase 3: Predeploying priority resources------------------------------
[INFO][2023-01-30 11:04:05 +0800] Deploying ConfigMap/demo-configmap-data (timeout: 30s)
[INFO][2023-01-30 11:04:05 +0800] Successfully deployed in 0.1s: ConfigMap/demo-configmap-data
[INFO][2023-01-30 11:04:05 +0800]
[INFO][2023-01-30 11:04:05 +0800]
[INFO][2023-01-30 11:04:05 +0800] ----------------------------------Phase 4: Deploying all resources----------------------------------
[INFO][2023-01-30 11:04:05 +0800] Deploying resources:
[INFO][2023-01-30 11:04:05 +0800] - ConfigMap/demo-configmap-data (timeout: 30s)
[INFO][2023-01-30 11:04:05 +0800] - PodTemplate/demo-pod-template-runner (timeout: 300s)
[INFO][2023-01-30 11:04:08 +0800] The following resources were pruned: podtemplate/pod-template-runner
[INFO][2023-01-30 11:04:09 +0800] Successfully deployed in 3.8s: ConfigMap/demo-configmap-data, PodTemplate/demo-pod-template-runner
[INFO][2023-01-30 11:04:09 +0800]
[INFO][2023-01-30 11:04:09 +0800] ------------------------------------------Result: SUCCESS-------------------------------------------
[INFO][2023-01-30 11:04:09 +0800] Pruned 1 resource and successfully deployed 2 resources
[INFO][2023-01-30 11:04:09 +0800]
[INFO][2023-01-30 11:04:09 +0800] Successful resources
[INFO][2023-01-30 11:04:09 +0800] ConfigMap/demo-configmap-data Available
[INFO][2023-01-30 11:04:09 +0800] PodTemplate/demo-pod-template-runner Available
执行krane run
,
krane run $NAMESPACE $CONTEXT --arguments="hello world!" --command="echo" --template=demo-pod-template-runner
输出日志,
[INFO][2023-01-30 11:05:15 +0800]
[INFO][2023-01-30 11:05:15 +0800] -------------------------------------Phase 1: Initializing task-------------------------------------
[INFO][2023-01-30 11:05:15 +0800] Validating configuration
[INFO][2023-01-30 11:05:15 +0800] Using namespace 'demo' in context 'k8s-admin@local'
[INFO][2023-01-30 11:05:15 +0800] Using template 'demo-pod-template-runner'
[INFO][2023-01-30 11:05:15 +0800]
[INFO][2023-01-30 11:05:15 +0800] ----------------------------------------Phase 2: Running pod----------------------------------------
[INFO][2023-01-30 11:05:15 +0800] Creating pod 'task-runner-6f8ddd03da6dd27e'
[INFO][2023-01-30 11:05:15 +0800] Pod creation succeeded
[INFO][2023-01-30 11:05:15 +0800]
[INFO][2023-01-30 11:05:15 +0800] --------------------------------------Phase 3: Streaming logs---------------------------------------
[INFO][2023-01-30 11:05:15 +0800] Streaming logs from Pod/task-runner-6f8ddd03da6dd27e container 'task-runner':
[INFO][2023-01-30 11:05:26 +0800] hello world!
[INFO][2023-01-30 11:05:28 +0800] Successfully ran in 13.1s: Pod/task-runner-6f8ddd03da6dd27e
[INFO][2023-01-30 11:05:28 +0800]
[INFO][2023-01-30 11:05:28 +0800] ------------------------------------------Result: SUCCESS-------------------------------------------
[INFO][2023-01-30 11:05:28 +0800] Successfully ran 1 resource
[INFO][2023-01-30 11:05:28 +0800]
[INFO][2023-01-30 11:05:28 +0800] Successful resources
[INFO][2023-01-30 11:05:28 +0800] Pod/task-runner-6f8ddd03da6dd27e Succeeded
krane render
是一个将ERB模板渲染成原始Kubernetes YAML的工具。它对输出YAML很有用,可以传递给其他工具,用于验证或自省。
自省(introspection)是机器人API、能力、监控及被监控功能操作的基础。
cat << EOF | krane render --bindings=current_sha=Changeme -f - > web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
annotations:
shipit.shopify.io/restart: "true"
labels:
name: web-deployment
spec:
replicas: 1
selector:
matchLabels:
name: web-deployment
progressDeadlineSeconds: 60
template:
metadata:
labels:
name: web-deployment
spec:
containers:
- name: web
image: busybox
imagePullPolicy: IfNotPresent
command: ["tail", "-f", "/dev/null"]
ports:
- containerPort: 80
name: http
env:
- name: GITHUB_REV
value: "<%= current_sha %>"
- name: sidecar
image: busybox
imagePullPolicy: IfNotPresent
command: ["tail", "-f", "/dev/null"]
EOF
输出日志,
[INFO][2023-01-30 11:40:48 +0800]
[INFO][2023-01-30 11:40:48 +0800] ---------------------------------Phase 1: Initializing render task----------------------------------
[INFO][2023-01-30 11:40:48 +0800] Validating configuration
[INFO][2023-01-30 11:40:48 +0800]
[INFO][2023-01-30 11:40:48 +0800] -----------------------------------Phase 2: Rendering template(s)-----------------------------------
[INFO][2023-01-30 11:40:48 +0800] Rendering from_stdin.yml.erb...
[INFO][2023-01-30 11:40:48 +0800] Rendered from_stdin.yml.erb
[INFO][2023-01-30 11:40:48 +0800]
[INFO][2023-01-30 11:40:48 +0800] ------------------------------------------Result: SUCCESS-------------------------------------------
[INFO][2023-01-30 11:40:48 +0800] Successfully rendered 1 template(s)
[INFO][2023-01-30 11:40:48 +0800]
查看生成的web-deployment.yaml
,
cat web-deployment.yaml
输出结果,
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
annotations:
shipit.shopify.io/restart: "true"
labels:
name: web-deployment
spec:
replicas: 1
selector:
matchLabels:
name: web-deployment
progressDeadlineSeconds: 60
template:
metadata:
labels:
name: web-deployment
spec:
containers:
- name: web
image: busybox
imagePullPolicy: IfNotPresent
command: ["tail", "-f", "/dev/null"]
ports:
- containerPort: 80
name: http
env:
- name: GITHUB_REV
value: "Changeme"
- name: sidecar
image: busybox
imagePullPolicy: IfNotPresent
command: ["tail", "-f", "/dev/null"]
由于Kubernetes的Secret只有base64编码,因此Kubernetes的Secret不应该被提交到你的仓库。相反,krane支持从模板目录中的加密ejson文件中生成Secret。下面示例展示如何使用这一功能。
先安装ejson,
sudo gem install ejson
生成一个新的密钥对,
ejson keygen
输出结果,
Public Key:
0337c353428b0366c38423290daa1dab74abf2aebb0c0f16b97499b4dc579802
Private Key:
97bf189c7d64bfb010e7b7f5c2a5d961b03834529ff888c83198a6e647b6ebf9
配置为环境变量,
YOUR_PUBLIC_KEY=0337c353428b0366c38423290daa1dab74abf2aebb0c0f16b97499b4dc579802
YOUR_PRIVATE_KEY=97bf189c7d64bfb010e7b7f5c2a5d961b03834529ff888c83198a6e647b6ebf9
用新的密钥对在你的目标命名空间创建一个Kubernetes秘密,
kubectl create secret generic ejson-keys --from-literal=$YOUR_PUBLIC_KEY=$YOUR_PRIVATE_KEY --namespace=$NAMESPACE
警告:不要使用
apply
来创建ejson-keys
Secret,如果ejson-keys
是可修改的,则 krane 会失败。这一保障措施是为了防止你的私钥被意外删除。
(可选但强烈建议)将密钥对备份到安全的地方,如密码管理器,以备灾难恢复之用。
在你的模板目录中(与你的Kubernetes模板一起),创建secrets.ejson
,其格式如下所示。对于TLS Secret,_type
Secret的值应该是 kubernetes.io/tls
,对于所有其他的Secret则是 Opaque
。数据键必须是一个json对象,但其键和值可以是你需要的任何东西。
cat << EOF > secrets.ejson
{
"_public_key": "$YOUR_PUBLIC_KEY",
"kubernetes_secrets": {
"catphotoscom": {
"_type": "kubernetes.io/tls",
"data": {
"tls.crt": "cert-data-here",
"tls.key": "key-data-here"
}
},
"monitoring-token": {
"_type": "Opaque",
"data": {
"api-token": "token-value-here"
}
}
}
}
EOF
加密文件,
ejson encrypt secrets.ejson
提交加密后的文件并进行部署。部署将从 kubernetes_secrets 密钥中的数据创建Secret。ejson文件必须包含在传递给–filenames的资源中,它不能通过stdin读取。
krane deploy $NAMESPACE $CONTEXT -f secrets.ejson
输出日志,
[INFO][2023-01-30 12:05:24 +0800]
[INFO][2023-01-30 12:05:24 +0800] ------------------------------------Phase 1: Initializing deploy------------------------------------
[INFO][2023-01-30 12:05:24 +0800] All required parameters and files are present
[INFO][2023-01-30 12:05:24 +0800] Discovering resources:
[INFO][2023-01-30 12:05:25 +0800] - Secret/catphotoscom (from ejson)
[INFO][2023-01-30 12:05:25 +0800] - Secret/monitoring-token (from ejson)
[INFO][2023-01-30 12:05:29 +0800]
[INFO][2023-01-30 12:05:29 +0800] ----------------------------Phase 2: Checking initial resource statuses-----------------------------
[INFO][2023-01-30 12:05:29 +0800] Secret/catphotoscom Not Found
[INFO][2023-01-30 12:05:29 +0800] Secret/monitoring-token Not Found
[INFO][2023-01-30 12:05:29 +0800]
[INFO][2023-01-30 12:05:29 +0800] ------------------------------Phase 3: Predeploying priority resources------------------------------
[INFO][2023-01-30 12:05:29 +0800] Deploying resources:
[INFO][2023-01-30 12:05:29 +0800] - Secret/catphotoscom (timeout: 30s)
[INFO][2023-01-30 12:05:29 +0800] - Secret/monitoring-token (timeout: 30s)
[INFO][2023-01-30 12:05:29 +0800] Successfully deployed in 0.2s: Secret/catphotoscom, Secret/monitoring-token
[INFO][2023-01-30 12:05:29 +0800]
[INFO][2023-01-30 12:05:29 +0800]
[INFO][2023-01-30 12:05:29 +0800] ----------------------------------Phase 4: Deploying all resources----------------------------------
[INFO][2023-01-30 12:05:29 +0800] Deploying resources:
[INFO][2023-01-30 12:05:29 +0800] - Secret/catphotoscom (timeout: 30s)
[INFO][2023-01-30 12:05:29 +0800] - Secret/monitoring-token (timeout: 30s)
[INFO][2023-01-30 12:05:33 +0800] The following resources were pruned: configmap/demo-configmap-data, podtemplate/demo-pod-template-runner
[INFO][2023-01-30 12:05:33 +0800] Successfully deployed in 4.0s: Secret/catphotoscom, Secret/monitoring-token
[INFO][2023-01-30 12:05:33 +0800]
[INFO][2023-01-30 12:05:33 +0800] ------------------------------------------Result: SUCCESS-------------------------------------------
[INFO][2023-01-30 12:05:33 +0800] Pruned 2 resources and successfully deployed 2 resources
[INFO][2023-01-30 12:05:33 +0800]
[INFO][2023-01-30 12:05:33 +0800] Successful resources
[INFO][2023-01-30 12:05:33 +0800] Secret/catphotoscom Available
[INFO][2023-01-30 12:05:33 +0800] Secret/monitoring-token Available
注意:由于ejson密钥中的前导下划线用于跳过相关值的加密,
krane
在为Kubernetes Secret数据创建密钥时将剥离这些前导下划线。例如,鉴于下面的ejson数据,monitoring-token
的Secret将有键api-token
和propety
(不是_property
)。{ "_public_key": "YOUR_PUBLIC_KEY", "kubernetes_secrets": { "monitoring-token": { "_type": "kubernetes.io/tls", "data": { "api-token": "EJ[ENCRYPTED]", "_property": "some unencrypted value" } } }
查看Secret,
kubectl describe secret catphotoscom -n $NAMESPACE
输出结果,
Name: catphotoscom
Namespace: demo
Labels: name=catphotoscom
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.key: 13 bytes
tls.crt: 14 bytes
[oracle@almalinux9 krane]$ kubectl get secret catphotoscom -n $NAMESPACE -o yaml
apiVersion: v1
data:
tls.crt: Y2VydC1kYXRhLWhlcmU=
tls.key: a2V5LWRhdGEtaGVyZQ==
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","data":{"tls.crt":"Y2VydC1kYXRhLWhlcmU=","tls.key":"a2V5LWRhdGEtaGVyZQ=="},"kind":"Secret","metadata":{"annotations":{},"labels":{"name":"catphotoscom"},"name":"catphotoscom","namespace":"demo"},"type":"kubernetes.io/tls"}
creationTimestamp: "2023-01-30T04:05:29Z"
labels:
name: catphotoscom
name: catphotoscom
namespace: demo
resourceVersion: "43777"
uid: b727fcdf-edf2-4532-89bf-4ea3cf6716d9
type: kubernetes.io/tls
完结!