k8s.gcr.io改為registry.k8s.io

新聞:k8s.gcr.io Redirect to registry.k8s.io – What You Need to Know | Kubernetes

簡單的說,k8s.gcr.io 要被關掉了,所以從 k8s.gcr.io 拉取的 image ,未來會有影響,例如砍掉 pod 以後,有可能拉不到 image 了。

所以要找出所有使用 k8s.gcr.io 的 deployment/statefulset/pod … 資源,方法有兩種。

第1種是用 kubectl 來找

kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" |\
tr -s '[[:space:]]' '\n' |\
sort |\
uniq -c

簡單的說,就是列出所有 pod 的 YAML,取出裡面的 image ,整理過以後,列出來。

第二種是用 kubectl krew 安裝 community-images plugin

kubectl krew install community-images
kubectl community-images

使用以上其中一種方法找到以後,該怎麼辦?

接下來就是用 kubectl edit 去修改 image 位址。

若是用 gitops 或 helm 的方法,作法也相似,就是去修改 manifest yaml ,然後重新佈署就可以了。

[Kubernetes]Pod rebalancing and allocations

文章來源:Pod rebalancing and allocations

簡單整理如下:

  • 應用程式是 deployment,有兩個 pod
  • 本來只有一個 node,兩個 pod 都會佈署在上面,所以如果一個 node 掛了,那麼應用程式就無法回應了。現在增加另外一個 node ,一般會預期 pod 移動一個到新的 node 上,但實際上 Kubernetes 不會做任何動作。

可以怎麼做?

Pod affinity

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: ellery-lab
spec:
  # 省略
  template:
    metadata:
      labels:
        app: MyTestApp
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: disktype
                operator: In
                values:
                - ssd

pod topology spread constraints

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: ellery-lab
spec:
  # 省略
  template:
    metadata:
      labels:
        app: MyTestApp
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            foo: bar

descheduler

這個是需要另外安裝的,安裝以後會在 kube-system 裏面找到,是一個 pod 。

The descheduler pod is run as a critical pod in the kube-system namespace to avoid being evicted by itself or by the kubelet

安裝完成以後,還需要設定 policy ,比較麻煩一些,但可以做到動態的處理,功能也比較多。

[Kubernetes]沒有downtime的佈署

來源:Zero-Downtime Rolling Deployments in Kubernetes | Rakuten Engineering Blog

以下是摘錄。

在刪除掉 Pod 之前,流量還是會導向 Pod,要處理這種狀況,就需要去處理 SIGTERM。

文章建議三種方法。

  • 在 pre-stop hook 裡用 sleep
  • 延遲應用程式中止
  • 動態延遲應用程式中止

在 pre-stop hook 裡用 sleep

spec:
  terminationGracePeriodSeconds: 60
  containers:
  - name: "{{APP_NAME}}"
    lifecycle:
      preStop:
        exec:
          command: ["/bin/sh","-c","sleep 20"]

缺點,sleep 的時間是要去測量跟估算的,每個應用程式不同。而且,pre-stop 的主要用途不是用來做這事情的。

延遲應用程式中止

這個是要改應用程式的程式碼。

這裡有舉一個 wrapper script 的例子

#!/bin/bash

HAPROXY_PID=-1

# wait for 10 seconds, then send a USR1 signal to HAproxy
kill_haproxy(){
  sleep 10
  kill -USR1 $HAPROXY_PID
}
 
# invoke kill_haproxy function when receives the TERM signal
trap kill_haproxy SIGTERM

# Support the user hitting Ctrl-C, but only in interactive shells
if [[ -t 1 ]] ; then
  trap 'kill -USR1 "$HAPROXY_PID"' SIGINT
fi
 
haproxy -f config.cfg & HAPROXY_PID=$!
 
if [ -z "$HAPROXY_PID" ]
then
  echo "haproxy: Haproxy failed to start"
else
  echo "haproxy: haproxy started"
fi

在 Dockerfile 就這樣用

FROM alpine:3.5

# install bash, tini and haproxy
RUN apk add --no-cache bash tini haproxy=2.0.14-r0
 
# Run tini
ENTRYPOINT ["/usr/local/bin/tini", "—"]
CMD ["/launcher.sh"]

缺點跟前者差不多。

動態延遲應用程式中止

這個說不一定可用,就跳過了。

結論

好好處理 SIGTERM 。

Shell Script 最佳實踐

來源:Shell Script Best Practice

這篇寫的很好,整理並摘錄裡面的內容

  1. 用 bash,不要用 zsh / fish
  2. 一開頭的 Sha-Bang 統一都寫 #!/usr/bin/env bash,這樣可以確保都是用相同的 shell 來執行,我自己是都寫 #!/bin/bash
  3. 副檔名用 .sh
  4. 第二行寫 set -o errexit,只要裏面有一行錯誤,就離開,不要繼續。
  5. 第三行寫 set -o nounset,只要有未設定的變數,就離開,不要繼續。
  6. 第四行寫 set -o pipefail,只要 pipe 過程中的指令有錯誤,就離開,不要繼續。
  7. 加上判斷 TRACE 環境參數是否存在的腳本,當有設定這個環境變數時,就加上 set -o xtrace,這可以幫助除錯。
  8. 儘量使用 [[ ]]取代 [ ][[ ]]是 bash內建的關鍵字,基本上作用跟 []或 test 一樣,可以減少額外消耗,而且有更多功能。
  9. 存取變數時,前後都加上雙引號。
  10. 函式裏面用 local 宣告變數。
  11. 加上 -h--help來說明自己怎麼使用。
  12. 印出錯誤訊息時,要導向到 stderr :echo 'Something unexpected happened' >&2
  13. 呼叫指令若有帶參數,最好帶長的,例如用 --silent代替 -s,這樣可讀性比較高。
  14. 一開始就切換到腳本的目錄,例如: cd "$(dirname "$0")" 我想這個應該是要確定腳本所要作用的目錄,所以加上註解,或是印出當前所在目錄,都對於後續維護的人會很有幫助。
  15. shellcheck來檢查腳本

作者有提供一個範本,可以直接複製來修改:

#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail
if [[ "${TRACE-0}" == "1" ]]; then
    set -o xtrace
fi

if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then
    echo 'Usage: ./script.sh arg-one arg-two

This is an awesome bash script to make your life better.

'
    exit
fi

cd "$(dirname "$0")"

main() {
    echo do awesome stuff
}

main "$@"

基本上就包含了前面所提到的重點,這裡額外一提的是有 main,這對於理解腳本來說,也是很重要的事情。

timemachineeditor

事情是在去年發生的,那時是在家辦公,卻發現 MBP 慢的要命,網速也變慢,後來查了一下,才發現是 MBP 一直在那邊做時光機備份。

這下就麻煩了,改為手動,又怕忘記,用自動又變慢,這可讓我好生困擾。請 Google 大神幫忙以後,找到有人推薦 timemachineeditor 這個工具。timemachineeditor 這個工具可以設定在不使用電腦的時間去做備份,這樣就解決我的問題了。

我是用 homebrew 安裝的

brew install --cask timemachineeditor

設定畫面很簡單,一看就會用了,這裡就不多說。

kubeaudit

網址:https://github.com/Shopify/kubeaudit

可以用來稽核 kubernetes 叢集的工具,檢查的項目有

  • 確保容器以非 root 身份執行
  • 確保容器的根目錄是唯讀
  • 移除有危險的 capability
  • 不執行 privileged
  • 陸續增加中

安裝

直接從 github release 下載二進位檔案,然後放到 /usr/local/bin 就可以了。

使用

有三種模式

  • Manifest mode
  • Local mode
  • Cluster mode

Manifest mode

Manifest mode 就是掃檔案,意思是如果你有寫好的 yaml 檔案,kubeaudit 可以直接掃 yaml 檔案

kubeaudit all -f "/path/to/manifest.yml"

掃完會輸出掃描結果。

需要修正的話,可以用 autofix 來自動修正。

kubeaudit autofix -f "/path/to/manifest.yml"

怕改爛的話,可以輸出到另外一個檔案

kubeaudit autofix -f "/path/to/manifest.yml" -o "/path/to/fixed"

Cluster mode

Cluster mode 就是掃描當前的 Kubernetes 叢集,不要加上 -f 參數就可以

kubeaudit all

Local mode

Local mode 是在你管理多座 kubernetes 叢集時,可以指定 kubeconfig 跟 context,例如

kubeaudit all --kubeconfig "/path/to/config" --context my_cluster

設定

大部份掃描工具都會提供設定,讓開發者可以決定要掃描哪些項目,kubeaudit 也有,格式是 yaml 。

enabledAuditors:
  # Auditors are enabled by default if they are not explicitly set to "false"
  apparmor: false
  asat: false
  capabilities: true
  deprecatedapis: true
  hostns: true
  image: true
  limits: true
  mounts: true
  netpols: true
  nonroot: true
  privesc: true
  privileged: true
  rootfs: true
  seccomp: true
auditors:
  capabilities:
    # add capabilities needed to the add list, so kubeaudit won't report errors
    allowAddList: ['AUDIT_WRITE', 'CHOWN']
  deprecatedapis:
    # If no versions are specified and the'deprecatedapis' auditor is enabled, WARN
    # results will be genereted for the resources defined with a deprecated API.
    currentVersion: '1.22'
    targetedVersion: '1.25'
  image:
    # If no image is specified and the 'image' auditor is enabled, WARN results
    # will be generated for containers which use an image without a tag
    image: 'myimage:mytag'
  limits:
    # If no limits are specified and the 'limits' auditor is enabled, WARN results
    # will be generated for containers which have no cpu or memory limits specified
    cpu: '750m'
    memory: '500m'
  • enabledAuditors 是要啟用的稽核項目
  • auditors 下方則是每個稽核項目的設定

總結

透過使用 kubeaudit 這個工具,可以稽核 kubernetes 叢集,避免放上有危險的設定,是很實用的工具。

microk8s使用自建的mirror registry

文件在這邊:How to work with a private registry

設定方法很簡單,設定檔案位置在 /var/snap/microk8s/current/args/certs.d/ ,每個 registry server 都有一個對應的目錄,裏面會有 hosts.toml 。例如 docker.io ,目錄就是

/var/snap/microk8s/current/args/certs.d/docker.io ,hosts.toml 的內容是
server = "https://docker.io"

[host."https://registry-1.docker.io"]
  capabilities = ["pull", "resolve"]

要改為 mirror registry,就變為

server = "https://docker.io"

[host."http://your_registry_server/v2"]
  capabilities = ["pull", "resolve"]
  override_path = true

關鍵在於 [host.””] 裡的 server 位置還有 override_path = true

修改完成以後,重新啟動 microk8s 即可。

sudo snap restart microk8s

基本設定方法就是這樣。之前在看的時候因為眼花,一直想說為什麼會有 “‘ | sudo tee -a /var/snap/microk8s/current/args/certs.d/k8s.gcr.io/hosts.toml” 這一段,後來仔細看,才知道文件裡貼的是一個指令。

以後改為這樣,就可以不用去外部拉取,加快拉取 image 速度了。

trivy-operator

Trivy 是 AquaSecurity 開發的工具,它可以掃描漏洞與有問題的設定檔,而且這工具有開源出來,真的是很佛心。

Trivy 有提供 CLI ,可以搭配 CI 作映像檔掃描,它也有提供 Operator ,可以安裝到 Kubernetes/OpenShift 裡,在佈署容器以後,他會自動的掃描,並產出漏洞報告。

安裝

安裝相當簡單,這邊使用 helm 來安裝,主要是因為這樣好管理。安裝步驟是參考這份文件:Helm – Trivy Operator

加入 helm repository

helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm repo update

安裝

helm install trivy-operator aqua/trivy-operator \
  --namespace trivy-system \
  --create-namespace \
  --set="trivy.ignoreUnfixed=true" \
  --version 0.10.1

檢查

helm list -n trivy-system
kubectl get deployment -n trivy-system

應該會看到以下的輸出

$ helm list -n trivy-system
NAME                 NAMESPACE           REVISION    UPDATED                                 STATUS      CHART                       APP VERSION
trivy-operator   trivy-system    1           2021-01-27 20:09:53.158961 +0100 CET    deployed    trivy-operator-0.10.1   0.10.1

$ kubectl get deployment -n trivy-system
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
trivy-operator   1/1     1            1           11m

使用

安裝完成以後,Trivy 會自動開始對所有 deployment/daemonset/pod 等的 image 去做掃描。

可以用以下指令去看掃描報告的列表,報告有兩種,一種是安全漏洞的 (vulnerabilityreports) ,一種是稽核的 (configauditreports)

kubectl get vulnerabilityreports -A -o wide
kubectl get configauditreports -A -o wide

後續佈署上去的,也會自動掃描。

要看報告內容,可以用 get/describe 來察看

kubectl get vulnerabilityreport replicaset-nginx-5fbc65fff-nginx -o yaml
kubectl describe configauditreport replicaset-nginx-5fbc65fff

報告預設是 24 小時後刪除,然後重新掃描,如果要調整,可以修改 trivy-operator 這個 deployment 裡的 OPERATOR_SCANNER_REPORT_TTL 環境變數。

後續

後續延伸的議題是 trivy 的掃描依據是什麼呢?若在封閉的環境下,能否使用?若可以使用,又該如何更新呢?

結論

感謝 AquaSecurity 提供的這個工具,讓容器平台能更安全。

kubectl scale

看完這篇 Using Kubectl Scale 所整理的。

基本使用方式

kubectl scale --replicas=3 deployment/nginx-hello

有條件的 scale,可以指定只有在已經有 n 個 pod 的情況下,才去 scale,例如

kubectl scale --current-replicas=3 --replicas=5 deployment/demo-deployment

這就是說,只有在目前已經有 3 個 pod 的情況下,才做 scale。這可以避免在資源已經不足的情況下還去做 scale,讓整個 k8s 叢集更加不穩定。

對多個資源做 scale

kubectl scale --replicas=5 deployment/app deployment/database

對 default 這個 namespace 裡所有可以 scale 的資源去做 scale

kubectl scale --all --replicas=5 --namespace=default deployment

也可以用 selector 去篩選,例如針對所有 app-name=demo-app 的 deployment 去做 scale

kubectl scale --replicas=5 --selector=app-name=demo-app deployment

要做 scale 還有其他方法:

  1. 更動 yaml 裡的 spec.replicas
  2. 使用 HPA (Horizontal Pod Autoscaling)

最佳實踐

  • 避免經常性的做 scale
  • scale 到 0 的時候,表示應用程式會停止服務
  • 確定選到正確的資源做 scale
  • 使用 --current-replicas 來避免意外。

yq

jq 這個工具可以用查詢語法去查詢 json 檔案裡的指定內容,很方便。基本上 yaml 可以直接轉換為 json ,因此若先把 yaml 轉換為 json,再用 jq 查詢也是可以的。

只是多了一道轉換,是稍嫌麻煩一點,那麼 yaml 檔案是不是也有類似的工具呢?

答案是有的,我找到兩個實作,一個是使用 python 實作,一個是使用 go 實作。

查詢語法跟 jq 很相似,這部份可以參考 jq https://stedolan.github.io/jq/