用戶數從 0 到億,我的 K8s 踩坑血淚史

  • 2019 年 10 月 3 日
  • 筆記

file
作者 | 平名 阿里服務端開發技術專家

導讀:容器服務 Kubernetes 是目前炙手可熱的雲原生基礎設施,作者過去一年上線了一個用戶數極速增長的應用:該應用一個月內日活用戶從零至四千萬,用戶數從零到一億的裂變式增長,充分享受了容器服務快速簡便的擴容操作和高可用特性。作者使用容器服務 Kubernetes 集群將公司內系統完全上雲 1 年多,本篇文章記錄了其中的踩坑與優化記錄。

關注「阿里巴巴雲原生」公眾號,回復關鍵詞「資料」,即可獲得 2019 全年meetup 活動 PPT 合集及 K8s 最全知識圖譜。

創建集群

創建集群時,做好規劃,選擇優化好的集群配置,可以大大減少後期運維工作,其中部分集群的配置在建立後再也沒法修改或者修改極其麻煩。

集群規劃

            Terway 是阿里雲容器服務自研的網路插件,功能上完全兼容 Flannel,如果保守,還是使用 Flannel  

  • Pod 網路 CIDR

默認 16 的大網段,有效的網段或者其子網 10.0.0.0/8,172.16-31.0.0/12-16,192.168.0.0/16

  • Service CIDR
    • 默認 20 的網段,可選:10.0.0.0/16-24,172.16-31.0.0/16-24,192.168.0.0/16-24
    • 網段不能衝突重複,建立後沒法修改;
    • 多個區域的多個交換機。
  • 公網訪問 ApiServer
    • 對於線上等安全要求高的集群,可以選擇不暴露 apiserver, 只有私網 SLB, 但是這樣沒法使用雲效發布;
    • 日常預發等集群,可以暴露公網 SLB 到 apiserver, 集群建立後立即為 slb 建立訪問控制,限制 slb 只能雲效訪問;

註: K8s 每次安全漏洞幾乎都與 ApiServer 有關,對於線上 K8s 集群,要及時升級修補程式,或者不開放公網 apiserver,使用嚴格的安全組和訪問控制。

  • 安全組
    • 設置安全組限定訪問範圍,為 master 與 worker 機器使用。

 

  • Master 機器規劃

   為了高可用,一般使用 3 節點,Master 選擇規則如下:

節點數  master 規格
1-5個 4C8G
6-20個節點 4C16G
21-100個節點 8C32G
100-200個節點 16C64G

master 機器的存儲建議高性能的 50-100G SSD,因為會運行 ETCD,作業系統佔用不超過 8G。

  • Worker 機器規劃
    • 阿里雲首推神龍機器,沒有神龍機器的區域,選用高配 ECS,配置規格根據部署的 POD 規格乘以一定倍數,比如 Java 應用 pod 一般選擇 4C8G,ECS 則購買 32C64G 或者 64C128G 為好,設置部署的時候為 pod 設置固定的 request/limit;
    • 我們選用的機器配置:
      • 32C64G ECS
      • 存儲。系統盤:100G SSD,  數據盤:400G 高效雲盤
      • 作業系統:centos 7.4 64 位

集群建立與配置

建立集群時設置:

  • 通過控制台建立集群,阿里雲容器服務提供的非常簡易的一鍵部署集群功能,通過嚮導完成 K8S 集群的建立;
  • 按照以上規劃設置 master,worker 節點,掛載 /var/lib/docker 到數據盤;
  • 設置合理的 Pod 網路 CIDR, Service CIDR ip 網段;
  • 設置合理的安全策略,是否暴露 apiserver(需要直接雲效發布的,需要開放公網暴露,並做嚴格的訪問控制);
  • ingress 選擇安全,可以使用內網,如果需要公網,可以在控制台很方便建立,同時做好訪問控制;
  • kube-proxy 模式,因為 iptables 模式在更新一條規則時把 iptables 鎖住引發的性能問題,建議使用 IPVS 模式;
  • 節點 POD 數量,默認 128 太大,一個節點不可能部署這麼多,建議改為 64;
  • 節點服務埠訪問 (NodePort,SLB),可以適當擴大,默認的也一般足夠用。

集群配置修改:

部署設置

無狀態部署

使用無狀態部署 Deployment,參考這篇文章實現分批發布。
優化設置模板: 

apiVersion: apps/v1beta2  kind: Deployment  metadata:    annotations:      deployment.kubernetes.io/revision: '34'  # 標籤,映射 service    labels:      app: {app_name}-aone    name: {app_name}-aone-1    namespace: {app_name}  spec:    progressDeadlineSeconds: 600    replicas: 1    revisionHistoryLimit: 10    selector:      matchLabels:        app: {app_name}-aone  # 批量重啟更新策略    strategy:      rollingUpdate:        maxSurge: 25%        maxUnavailable: 25%      type: RollingUpdate    template:      metadata:        labels:          app: {app_name}-aone      spec:        containers:         # 環境變數增加時區          - env:              - name: TZ                value: Asia/Shanghai          - image: >-              registry-vpc.cn-north-2-gov-1.aliyuncs.com/{namespace}/{app_name}:20190820190005            imagePullPolicy: Always            # 啟動前執行優雅下線摘除 服務註冊            lifecycle:              preStop:                exec:                  command:                    - sudo                    - '-u'                    - admin                    - /home/{user_name}/{app_name}/bin/appctl.sh                    - {app_name}                    - stop            # 存活檢查,強烈建議設置            livenessProbe:              failureThreshold: 10              initialDelaySeconds: 30              periodSeconds: 10              successThreshold: 1              tcpSocket:                port: 5900              timeoutSeconds: 1            name: {app_name}-aone            # 就緒檢查,強烈建議設置            readinessProbe:              failureThreshold: 10              initialDelaySeconds: 30              periodSeconds: 10              successThreshold: 1              tcpSocket:                port: 5900              timeoutSeconds: 1            # 資源限制,這個一定要合理設置            resources:              limits:                cpu: '4'                memory: 8Gi              requests:                cpu: '4'                memory: 8Gi            terminationMessagePath: /dev/termination-log            terminationMessagePolicy: File            # 日誌存放目錄,映射到節點的/var/lib/docker/logs 數據盤,應用日誌目錄設置到/home/{user_name}/logs 下            volumeMounts:              - mountPath: /home/{user_name}/logs                name: volume-1553755418538        dnsPolicy: ClusterFirst        ## 私有鏡像倉庫的密鑰,從保密欄位獲取        imagePullSecrets:          - name: {app_name}-987        restartPolicy: Always        schedulerName: default-scheduler        securityContext: {}        terminationGracePeriodSeconds: 30        # 日誌存放目錄,映射到節點的/var/lib/docker/logs 數據盤        volumes:          - hostPath:              path: /var/lib/docker/logs/{app_name}              type: ''            name: volume-1553755418538

 

服務設置

因為容器服務的 Cloud Controller Manager 會同步刪除 service 建立關聯的 SLB,為了防止 service 配置修改誤刪除 slb 故障,並導致域名、安全等配置需要修改的坑,強烈建議 service 與 slb 解耦,service 採用 NodePort 的方式,slb 另外建立後端伺服器指向集群節點,如果需要透傳真實 IP,並考慮負載均衡,需要遵守一定的配置規則和方法,參考這個文章。

NodePort:

apiVersion: v1  kind: Service  metadata:    name: {app_name}    namespace: {namespaces}  spec:    clusterIP: 10.1.50.65  ## 策略關係到是否透傳真實 IP    externalTrafficPolicy: Cluster    ports:      - name:  {app_name}-80-7001        nodePort: 32653        port: 80        protocol: TCP        targetPort: 7001      - name:  {app_name}-5908-5908        nodePort: 30835        port: 5108        protocol: TCP        targetPort: 5108    selector:      app:  {app_name}    sessionAffinity: None    type: NodePort  status:    loadBalancer: {}

然後在負載均衡管理頁面,選擇後端伺服器指向集群的 worker 機器,設置埠為以上服務的埠:32653,完成配置,這樣在集群 service 修改或者刪除重建的時候,slb 不會被集群的 CCM 刪除,不會涉及到域名,安全等配置修改。同時,可以設置一些策略,需要升級修改服務配置時,分批切流等。

總結

阿里雲容器服務控制台雖然是雲上新產品,提供了極其簡單的一鍵部署功能,以及簡便的控制台管理。過去一年中,筆者一路見識阿里雲容器服務控制台從簡陋向強大的轉變過程,雖然多次踩坑,但阿里雲容器服務同學認真負責和極好的服務態度讓人佩服。

容器服務管理控制台還需要更多的考慮實際運維需求,並緊密結合已有的雲產品,比如雲效、EDAS、雲監控、日誌服務等,以應用為單位,提供更好服務。


掃描下方二維碼添加小助手,與 8000 位雲原生愛好者討論技術趨勢,實戰進階!
進群暗號:公司-崗位-城市
file

Tags: