通過 MicroK8s 搭建你的 K8s 環境

  • 2019 年 10 月 8 日
  • 筆記

本文使用「署名 4.0 國際 (CC BY 4.0)」許可協議,歡迎轉載、或重新修改使用,但需要註明來源。 署名 4.0 國際 (CC BY 4.0)

本文作者: 蘇洋

創建時間: 2019年09月08日 統計字數: 15314字 閱讀時間: 31分鐘閱讀 本文鏈接: https://soulteary.com/2019/09/08/build-your-k8s-environment-with-microk8s.html

通過 MicroK8s 搭建你的 K8s 環境

去年的時候,我曾經寫過如何簡單搭建 Kubernetes 集群,當時使用的是官方的工具箱:Kubeadm,這個方案對於只是想試試的同學來說,還是過於複雜。這裡介紹一款簡單的工具:MicroK8s。

官方給這款工具的人設是「無需運維的 Kubernetes ,服務於工作站、物聯網。」最大的價值在於可以快速搭建單節點的容器編排系統,用於生產試驗。

官方網站里的文檔有簡單介紹如何安裝使用,但是卻未曾考慮安裝過程存在網路問題的神州大陸的同學們,本文將結合這種情況聊聊。

寫在前面

官方在早些時候宣布接下來將會使用 Containerd 替換 docker

The upcoming release of v1.14 Kubernetes will mark the MicroK8s switch to Containerd and enhanced security. As this is a big step forward we would like to give you a heads up and offer you a preview of what is coming. Give it a test drive with: snap install microk8s –classic –channel=1.13/edge/secure-containerd You can read more in our blog 117, and the respective pill request 13 Please, let us know 5 how we can make this transition smoother for you. Thanks

社區里已經有用戶諮詢/吐槽過了,這裡考慮減少變化,暫時還是以使用 docker 作為容器封裝的 1.13 ,新版本留給下一篇「折騰」吧。

使用 SNAP 安裝 MicroK8S

snap 是 *canonical * 公司給出的更「高級」的包管理的解決方案,最早應用在 Ubuntu Phone 上。

使用 snap 安裝 K8s 確實很簡單,就像下面一樣,一條命令解決問題:

snap install microk8s --classic --channel=1.13/stable

但是這條命令如果不是在海外主機上執行,應該會遇到安裝緩慢的問題。

snap install microk8s --classic --channel=1.13/stable  Download snap "microk8s" (581) from channel "1.13/stable"                                                                                            0% 25.9kB/s 2h32m

想要解決這個問題,暫時只能給 snap 添加代理來解決問題,snap 不會讀取系統的環境變數,只讀取應用的變數文件。

使用下面的命令可以方便的修改 snap 的環境變數,但是默認編輯器是 * nano *,非常難用。

systemctl edit snapd.service

這裡可以先更新編輯器為我們熟悉的 * vim *:

sudo update-alternatives --install "$(which editor)" editor "$(which vim)" 15  sudo update-alternatives --config editor

互動式終端需要我們手動輸入數字,然後按下回車確認選擇:

There are 5 choices for the alternative editor (providing /usr/bin/editor).      Selection    Path                Priority   Status  ------------------------------------------------------------  * 0            /bin/nano            40        auto mode    1            /bin/ed             -100       manual mode    2            /bin/nano            40        manual mode    3            /usr/bin/vim         15        manual mode    4            /usr/bin/vim.basic   30        manual mode    5            /usr/bin/vim.tiny    15        manual mode    Press <enter> to keep the current choice[*], or type selection number: 5  update-alternatives: using /usr/bin/vim.tiny to provide /usr/bin/editor (editor) in manual mode

再次執行上面編輯環境變數的命令,添加一段代理配置:

[Service]    Environment="HTTP_PROXY=http://10.11.12.123:10240"  Environment="HTTPS_PROXY=http://10.11.12.123:10240"  Environment="NO_PROXY=localhost,127.0.0.1,192.168.0.0/24,*.domain.ltd"

再次執行安裝,安裝進度起飛:

snap install microk8s --classic --channel=1.13/stable    Download snap "microk8s" (581) from channel "1.13/stable"                                                                                           31% 14.6MB/s 11.2s

如果速度沒有變化,可以考慮重載 snap 服務。

systemctl daemon-reload && systemctl restart snapd

如果上面的操作一切順利,你將會看到類似下面的日誌:

snap install microk8s --classic --channel=1.13/stable  microk8s (1.13/stable) v1.13.6 from Canonical✓ installed

執行列表命令,可以看到當前 snap 已經安裝好的工具:

snap list  Name      Version  Rev   Tracking  Publisher   Notes  core      16-2.40  7396  stable    canonical✓  core  microk8s  v1.13.6  581   1.13      canonical✓  classic

之前 獨立安裝 K8s 需要先安裝 docker,而使用 snap 安裝的話,這一切都是默認就緒的。

microk8s.docker version  Client:   Version:           18.09.2   API version:       1.39   Go version:        go1.10.4   Git commit:        6247962   Built:             Tue Feb 26 23:56:24 2019   OS/Arch:           linux/amd64   Experimental:      false    Server:   Engine:    Version:          18.09.2    API version:      1.39 (minimum version 1.12)    Go version:       go1.10.4    Git commit:       6247962    Built:            Tue Feb 12 22:47:29 2019    OS/Arch:          linux/amd64    Experimental:     false

獲取 Kubernetes 依賴鏡像

想要使用 Kubernetes,除了安裝 MicroK8s 外,還需要獲取它依賴的工具鏡像。然而鏡像的獲取還是需要費點功夫的,首先獲取 1.13 版本的 MicroK8s 程式碼:

git clone --single-branch --branch=1.13 https://github.com/ubuntu/microk8s.git

然後獲取其中聲明的容器鏡像列表:

grep -ir 'image:' * | awk '{print $3 $4}' | uniq

因為官方程式碼的奔放,我們會獲得長得奇形怪狀的鏡像名稱:

localhost:32000/my-busybox  elasticsearch:6.5.1  alpine:3.6  docker.elastic.co/kibana/kibana-oss:6.3.2  time="2016-02-04T07:53:57.505612354Z"level=error  cdkbot/registry-$ARCH:2.6  ...  ...  quay.io/prometheus/prometheus  quay.io/coreos/kube-rbac-proxy:v0.4.0  k8s.gcr.io/metrics-server-$ARCH:v0.2.1  cdkbot/addon-resizer-$ARCH:1.8.1  cdkbot/microbot-$ARCH  "k8s.gcr.io/cuda-vector-add:v0.1"  nginx:latest  istio/examples-bookinfo-details-v1:1.8.0  busybox  busybox:1.28.4

根據我們要部署的目標伺服器的具體需求,替換掉 $ARCH 變數,去掉無意義的鏡像名稱,整理好的列表如下:

k8s.gcr.io/fluentd-elasticsearch:v2.2.0  elasticsearch:6.5.1  alpine:3.6  docker.elastic.co/kibana/kibana-oss:6.3.2  cdkbot/registry-amd64:2.6  gcr.io/google_containers/defaultbackend-amd64:1.4  quay.io/kubernetes-ingress-controller/nginx-ingress-controller-amd64:0.22.0  jaegertracing/jaeger-operator:1.8.1  gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.7  gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.7  gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.7  k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3  k8s.gcr.io/heapster-influxdb-amd64:v1.3.3  k8s.gcr.io/heapster-grafana-amd64:v4.4.3  k8s.gcr.io/heapster-amd64:v1.5.2  cdkbot/addon-resizer-amd64:1.8.1  cdkbot/hostpath-provisioner-amd64:latest  quay.io/coreos/k8s-prometheus-adapter-amd64:v0.3.0  grafana/grafana:5.2.4  quay.io/coreos/kube-rbac-proxy:v0.4.0  quay.io/coreos/kube-state-metrics:v1.4.0  quay.io/coreos/addon-resizer:1.0  quay.io/prometheus/prometheus  quay.io/coreos/prometheus-operator:v0.25.0  quay.io/prometheus/alertmanager  quay.io/prometheus/node-exporter:v0.16.0  quay.io/coreos/kube-rbac-proxy:v0.4.0  k8s.gcr.io/metrics-server-amd64:v0.2.1  cdkbot/addon-resizer-amd64:1.8.1  nvidia/k8s-device-plugin:1.11  cdkbot/microbot-amd64  k8s.gcr.io/cuda-vector-add:v0.1  nginx:latest  istio/examples-bookinfo-details-v1:1.8.0  istio/examples-bookinfo-ratings-v1:1.8.0  istio/examples-bookinfo-reviews-v1:1.8.0  istio/examples-bookinfo-reviews-v2:1.8.0  istio/examples-bookinfo-reviews-v3:1.8.0  istio/examples-bookinfo-productpage-v1:1.8.0  busybox  busybox:1.28.4

將上面的列表保存為 package-list.txt 在網路通暢的雲伺服器上使用下面的腳本,可以將 K8s 依賴的工具鏡像離線保存:

PACKAGES=`cat ./package-list.txt`;    for package in $PACKAGES; do docker pull "$package"; done    docker images | tail -n +2 | grep -v "<none>" | awk '{printf("%s:%sn", $1, $2)}' | while read IMAGE; do      for package in $PACKAGES;      do          if [[ $package != *[':']* ]];then package="$package:latest"; fi            if [ $IMAGE == $package ];then              echo "[find image] $IMAGE"              filename="$(echo $IMAGE| tr ':' '-' | tr '/' '-').tar"              echo "[save as] $filename"              docker save ${IMAGE} -o $filename          fi      done  done

將鏡像轉存待部署伺服器的方式多種多樣,這裡提一種最簡單的方案: scp

PACKAGES=`cat ./package-list.txt`;    for package in $PACKAGES;  do      if [[ $package != *[':']* ]];then package="$package:latest";fi      filename="$(echo $package| tr ':' '-' | tr '/' '-').tar"      # 根據自己實際場景修改地址      scp "mirror-server:~/images/$filename" .      scp "./$filename" "deploy-server:"  done

如果順利你將看到類似下面的日誌:

k8s.gcr.io-fluentd-elasticsearch-v2.2.0.tar                                                                                         100%  140MB  18.6MB/s   00:07  elasticsearch-6.5.1.tar                                                                                                             100%  748MB  19.4MB/s   00:38  alpine-3.6.tar                                                                                                                      100% 4192KB  15.1MB/s   00:00  docker.elastic.co-kibana-kibana-oss-6.3.2.tar                                                                                       100%  614MB  22.8MB/s   00:26  cdkbot-registry-amd64-2.6.tar                                                                                                       100%  144MB  16.1MB/s   00:08  gcr.io-google_containers-defaultbackend-amd64-1.4.tar                                                                               100% 4742KB  13.3MB/s   00:00  ...  ...

最後在目標伺服器使用 docker load 命令導入鏡像即可。

ls *.tar | xargs -I {} microk8s.docker load -i {}

接下來可以正式安裝 K8s 啦。

正式開始安裝 Kubernetes

使用 MicroK8s 配置各種組件很簡單,只需要一條命令:

microk8s.enable dashboard dns ingress istio registry storage

完整的組件列表可以通過 microk8s.enable--help 來查看:

microk8s.enable --help  Usage: microk8s.enable ADDON...  Enable one or more ADDON included with microk8s  Example: microk8s.enable dns storage    Available addons:      dashboard    dns    fluentd    gpu    ingress    istio    jaeger    metrics-server    prometheus    registry    storage

執行 enable 順利的話,你將看到類似下面的日誌:

logentry.config.istio.io/accesslog created  logentry.config.istio.io/tcpaccesslog created  rule.config.istio.io/stdio created  rule.config.istio.io/stdiotcp created  ...  ...  Istio is starting  Enabling the private registry  Enabling default storage class  deployment.extensions/hostpath-provisioner created  storageclass.storage.k8s.io/microk8s-hostpath created  Storage will be available soon  Applying registry manifest  namespace/container-registry created  persistentvolumeclaim/registry-claim created  deployment.extensions/registry created  service/registry created  The registry is enabled  Enabling default storage class  deployment.extensions/hostpath-provisioner unchanged  storageclass.storage.k8s.io/microk8s-hostpath unchanged  Storage will be available soon

使用 microk8s.status 檢查各個組件的狀態:

microk8s is running  addons:  jaeger: disabled  fluentd: disabled  gpu: disabled  storage: enabled  registry: enabled  ingress: enabled  dns: enabled  metrics-server: disabled  prometheus: disabled  istio: enabled  dashboard: enabled

但是組件就緒,不代表 K8s 已經安裝就緒,使用 microk8s.inspect 排查下安裝部署結果:

Inspecting services    Service snap.microk8s.daemon-containerd is running    Service snap.microk8s.daemon-docker is running    Service snap.microk8s.daemon-apiserver is running    Service snap.microk8s.daemon-proxy is running    Service snap.microk8s.daemon-kubelet is running    Service snap.microk8s.daemon-scheduler is running    Service snap.microk8s.daemon-controller-manager is running    Service snap.microk8s.daemon-etcd is running    Copy service arguments to the final report tarball  Inspecting AppArmor configuration  Gathering system info    Copy network configuration to the final report tarball    Copy processes list to the final report tarball    Copy snap list to the final report tarball    Inspect kubernetes cluster     WARNING:  IPtables FORWARD policy is DROP. Consider enabling traffic forwarding with: sudo iptables -P FORWARD ACCEPT

解決方法很簡單,使用 ufw 添加幾條規則即可:

sudo ufw allow in on cbr0 && sudo ufw allow out on cbr0  sudo ufw default allow routed  sudo iptables -P FORWARD ACCEPT

再次使用 microk8s.inspect 命令檢查,會發現 WARNING 已經消失了。

但是 Kubernetes 真的安裝就緒了嗎?跟隨下一小節尋找答案吧。

解決 Kubernetes 不能正常啟動

在上面的操作順利之後完畢後,使用 microk8s.kubectlgetpods 查看當前 Kubernetes pods 狀態,如果看到 ContainerCreating ,那麼說明 Kubernetes 還需要一些額外的「修補工作」。

NAME                                      READY   STATUS              RESTARTS   AGE  default-http-backend-855bc7bc45-t4st8     0/1     ContainerCreating   0          16m  nginx-ingress-microk8s-controller-kgjtl   0/1     ContainerCreating   0          16m

使用 microk8s.kubectlgetpods--all-namespaces 查看詳細的狀態,不出意外的話,將看到類似下面的日誌輸出:

NAMESPACE            NAME                                              READY   STATUS              RESTARTS   AGE  container-registry   registry-7fc4594d64-rrgs9                         0/1     Pending             0          15m  default              default-http-backend-855bc7bc45-t4st8             0/1     ContainerCreating   0          16m  default              nginx-ingress-microk8s-controller-kgjtl           0/1     ContainerCreating   0          16m  ...  ...

首要的問題就是解決掉這個處於 Pending 狀態的容器。使用 microk8s.kubectl describe pod 可以快速查看當前這個問題 pod 的詳細狀態:

Events:    Type     Reason                  Age                 From                         Message    ----     ------                  ----                ----                         -------    Normal   Scheduled               22m                 default-scheduler            Successfully assigned default/default-http-backend-855bc7bc45-t4st8 to ubuntu-basic-18-04    Warning  FailedCreatePodSandBox  21m                 kubelet, ubuntu-basic-18-04  Failed create pod sandbox: rpc error: code = Unknown desc = failed pulling image "k8s.gcr.io/pause:3.1": Error response from daemon: Get https://k8s.gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)    Warning  FailedCreatePodSandBox  43s (x45 over 21m)  kubelet, ubuntu-basic-18-04  Failed create pod sandbox: rpc error: code = Unknown desc = failed pulling image "k8s.gcr.io/pause:3.1": Error response from daemon: Get https://k8s.gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

參考日誌輸出,可以發現,之前整理的依賴鏡像列表,還存在「漏網之魚」:MicroK8s 中還包含未寫在程式中,從遠程配置中獲取的鏡像。

對於這種情況,我們只能通過給 docker 添加代理來解決問題(或者手動一個一個來)。

編輯 MicroK8s 使用的 docker 環境變數配置文件 vi/var/snap/microk8s/current/args/dockerd-env,在其中添加代理配置,比如:

HTTPS_PROXY=http://10.11.12.123:10555  HTTPS_PROXY=http://10.11.12.123:10555  NO_PROXY=127.0.0.1

接著重啟 docker :

sudo systemctl restart snap.microk8s.daemon-docker.service

這一切就緒之後,執行下面的命令,重置 MicroK8s 並再次嘗試安裝各種組件:

microk8s.reset  microk8s.enable dashboard dns ingress istio registry storage

命令之後完畢之後,片刻之後再次執行 microk8s.kubectlgetpods 會發現所有的 pod 的狀態就都是 Running:

NAME                                      READY   STATUS    RESTARTS   AGE  default-http-backend-855bc7bc45-w62jd     1/1     Running   0          46s  nginx-ingress-microk8s-controller-m9lc2   1/1     Running   0          46s

使用 microk8s.kubectlgetpods--all-namespaces 繼續進行驗證:

NAMESPACE            NAME                                              READY   STATUS      RESTARTS   AGE  container-registry   registry-7fc4594d64-whjnl                         1/1     Running     0          2m  default              default-http-backend-855bc7bc45-w62jd             1/1     Running     0          2m  default              nginx-ingress-microk8s-controller-m9lc2           1/1     Running     0          2m  istio-system         grafana-59b8896965-xtc27                          1/1     Running     0          2m  istio-system         istio-citadel-856f994c58-fbc7c                    1/1     Running     0          2m  istio-system         istio-cleanup-secrets-9q8tw                       0/1     Completed   0          2m  istio-system         istio-egressgateway-5649fcf57-cbqlv               1/1     Running     0          2m  istio-system         istio-galley-7665f65c9c-l7grc                     1/1     Running     0          2m  istio-system         istio-grafana-post-install-sl6mb                  0/1     Completed   0          2m  istio-system         istio-ingressgateway-6755b9bbf6-hvnld             1/1     Running     0          2m  istio-system         istio-pilot-698959c67b-zts2v                      2/2     Running     0          2m  istio-system         istio-policy-6fcb6d655f-mx68m                     2/2     Running     0          2m  istio-system         istio-security-post-install-5d7bb                 0/1     Completed   0          2m  istio-system         istio-sidecar-injector-768c79f7bf-qvcjd           1/1     Running     0          2m  istio-system         istio-telemetry-664d896cf5-jz22s                  2/2     Running     0          2m  istio-system         istio-tracing-6b994895fd-z8jn9                    1/1     Running     0          2m  istio-system         prometheus-76b7745b64-fqvn9                       1/1     Running     0          2m  istio-system         servicegraph-5c4485945b-spf77                     1/1     Running     0          2m  kube-system          heapster-v1.5.2-64874f6bc6-8ghnr                  4/4     Running     0          2m  kube-system          hostpath-provisioner-599db8d5fb-kxtjw             1/1     Running     0          2m  kube-system          kube-dns-6ccd496668-98mvt                         3/3     Running     0          2m  kube-system          kubernetes-dashboard-654cfb4879-vzgk5             1/1     Running     0          2m  kube-system          monitoring-influxdb-grafana-v4-6679c46745-68vn7   2/2     Running     0          2m

如果你看到的結果類似上面這樣,說明 Kubernetes 是真的就緒了。

快速創建應用

安都安完了,總得試著玩玩看吧,當然,這裡不會隨大流的展示下管理後台就匆匆擱筆。

使用 kubectl 基於現成的容器創建一個 deployment:

microk8s.kubectl create deployment microbot --image=dontrebootme/microbot:v1

既然用上了最先進的編排系統,不體驗下自動擴容豈不是太可惜了:

microk8s.kubectl scale deployment microbot --replicas=2

將服務暴露出來,創建流量轉發:

microk8s.kubectl expose deployment microbot --type=NodePort --port=80 --name=microbot-service

使用 get 命令查看服務狀態:

microk8s.kubectl get all

如果一切順利的話,你將會看到類似下面的日誌輸出:

NAME                                          READY   STATUS    RESTARTS   AGE  pod/default-http-backend-855bc7bc45-w62jd     1/1     Running   0          64m  pod/microbot-7c7594fb4-dxgg7                  1/1     Running   0          13m  pod/microbot-7c7594fb4-v9ztg                  1/1     Running   0          13m  pod/nginx-ingress-microk8s-controller-m9lc2   1/1     Running   0          64m    NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE  service/default-http-backend   ClusterIP   10.152.183.13   <none>        80/TCP         64m  service/kubernetes             ClusterIP   10.152.183.1    <none>        443/TCP        68m  service/microbot-service       NodePort    10.152.183.15   <none>        80:31354/TCP   13m    NAME                                               DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE  daemonset.apps/nginx-ingress-microk8s-controller   1         1         1       1            1           <none>          64m    NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE  deployment.apps/default-http-backend   1/1     1            1           64m  deployment.apps/microbot               2/2     2            2           13m    NAME                                              DESIRED   CURRENT   READY   AGE  replicaset.apps/default-http-backend-855bc7bc45   1         1         1       64m  replicaset.apps/microbot-7c7594fb4                2         2         2       13m

可以看到我們剛剛創建的 Service 地址是 10.11.12.234:31354。使用瀏覽器訪問,可以看到應用已經跑起來啦。

本著「誰製造誰收拾」的綠色環保理念,除了「無腦」創建外,我們也需要學會如何治理(銷毀),使用 delete 命令,先銷毀 deployment :

microk8s.kubectl delete deployment microbot

執行完畢後日誌輸出會是下面一樣:

deployment.extensions "microbot" deleted

在銷毀 service 前,我們需要使用 get 命令先獲取所有的 service 的名稱:

microk8s.kubectl get services microbot-service    NAME               TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE  microbot-service   NodePort   10.152.183.15   <none>        80:31354/TCP   24m

得到了 service 名稱後,依舊是使用 delete 命令,刪除不需要的資源:

microk8s.kubectl delete service microbot-service

執行結果如下:

service "microbot-service" deleted

查看 Dashboard

估計還是有同學會想一窺 Dashboard 的狀況。

可以通過 microk8s.config 命令,先獲得當前伺服器監聽的 IP 地址:

microk8s.config  apiVersion: v1  clusters:  - cluster:      server: http://10.11.12.234:8080    name: microk8s-cluster  contexts:  - context:      cluster: microk8s-cluster      user: admin    name: microk8s  current-context: microk8s  kind: Config  preferences: {}  users:  - name: admin    user:      username: admin

可以看到,當前監聽的服務 IP 地址為 10.11.12.234,使用 proxy 命令,打開流量轉發:

microk8s.kubectl proxy --accept-hosts=.* --address=0.0.0.0

接著訪問下面的地址,就能看到我們熟悉的 Dashboard 啦:

http://10.11.12.234:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#!/login

其他

完整安裝下來,連著系統一共花費了接近 8G 的儲存空間,所以如果你打算持續使用的話,可以提前規划下磁碟空間,比如參考 遷移 Docker 容器儲存位置 把未來持續膨脹的 docker 鏡像包地址先做個遷移。

df -h    Filesystem      Size  Used Avail Use% Mounted on  udev            7.8G     0  7.8G   0% /dev  tmpfs           1.6G  1.7M  1.6G   1% /run  /dev/sda2        79G   16G   59G  21% /

最後

這篇文章成文於一個月之前,由於使用的還是 「Docker」 方案,理論來說時效性還是靠譜的,如果你遇到了什麼問題,歡迎討論溝通。

—EOF—