Step by Step!Kubernetes持續部署指南

2021-02-20 凡泰極客

凡泰極客導讀:

眾所周知,Kubernetes 是一款由 Google 發起的開源系統,目的在於提高集群環境下管理容器化應用的效率。有些人將其稱為容器編排平臺,而 Kubernetes 並非唯一的此類平臺。不過,相比其它對手,其享譽已盛,且知名度仍在不斷提高;更別說你一旦習慣上它,就會發現它真的十分易用。如果你依然好奇為何有人能夠愉快地和 Kubernetes 玩耍,答案就是——簡單。Kubernetes 能夠讓部署、管理多個項目所需的大量集群變得更加容易。

本文我們將詳細介紹如何將應用程式部署到Kubernetes,閱讀完本文之後,你將擁有一個高效的Kubernetes部署和持續交付工作流程。

持續集成是在每次應用程式更新時構建和測試的實踐。通過以少量的工作,更早地檢測到錯誤並立即解決。

集成完成並且所有測試都通過之後,我們就能夠添加持續交付到自動化發布和部署的流程中。使用CI/CD的項目可以更頻繁、更可靠地發布。

我們將使用Semaphore,這是一個快速、強大且易用地持續集成和交付(CI/CD)平臺,它能夠自動執行所有流程:

1、 安裝項目依賴項

2、 運行單元測試

3、 構建一個Docker鏡像

4、 Push鏡像到Docker Hub

5、 一鍵Kubernetes部署

對於應用程式,我們有一個Ruby Sinatra微服務,它暴露一些HTTP端點。該項目已包含部署所需的所有內容,但仍需要一些組件。

在開始操作之前,你需要登錄Github和Semaphore帳號。此外,為後續方便拉取或push Docker鏡像,你需要登錄Docker Hub。

接下來,你需要在計算機上安裝一些工具:

Git:處理代碼

curl:網絡的「瑞士軍刀」

kubectl:遠程控制你的集群

當然,千萬不要忘了Kubernetes。大部分的雲供應商都以各種形式提供此服務,選擇適合你的需求的即可。最低端的機器配置和集群大小足以運行我們示例的app。我喜歡從3個節點的集群開始,但你可以只用1個節點的集群。

集群準備好之後,從你的供應商中下載kubeconfig文件。有些允許你直接從其web控制臺下載,有些則需要幫助程序。我們需要此文件才能連接到集群。

有了這個,我們已經可以開始了。首先要做的是fork存儲庫。

在這篇文章中fork我們將使用的演示應用程式。

訪問semaphore-demo-ruby-kubernetes存儲庫,並且點擊右上方的Fork按鈕

點擊Clone or download按鈕並且複製地址

複製存儲庫:

$ git clone https://github.com/your_repository_path…

使用Semaphore連接新的存儲庫

1、 登錄到你的Semaphore

2、 點擊側邊欄的連結,創建一個新項目

3、 點擊你的存儲庫旁【Add Repository】按鈕

持續集成讓測試變得有趣並且高效。一個完善的CI 流水線能夠創建一個快速反饋迴路以在造成任何損失之前發現錯誤。我們的項目附帶一些現成的測試。

打開位於.semaphore/semaphore.yml的初始流水線文件,並快速查看。這個流水線描述了Semaphore構建和測試應用程式所應遵循的所有步驟。它從版本和名稱開始。

接下來是agent,它是為job提供動力的虛擬機。我們可以從3種類型中選擇:

agent:  machine:    type: e1-standard-2    os_image: ubuntu1804

Block(塊)、任務以及job定義了在流水線的每個步驟中要執行的操作。在Semaphore,block按照順序運行,與此同時,在block中的job也會並行運行。流水線包含2個block,一個是用於庫安裝,一個用於運行測試。

第一個block下載並安裝了Ruby gems。

- name: Install dependencies  task:    jobs:      - name: bundle install        commands:          - checkout          - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-master          - bundle install           - cache store gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock) .bundle

Checkout複製了Github裡的代碼。既然每個job都在完全隔離的機器裡運行,那麼我們必須依賴緩存(cache)來在job運行之間存儲和檢索文件。

blocks:  - name: Install dependencies    task:      jobs:        - name: bundle install          commands:            - checkout            - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-master            - bundle install             - cache store gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock) .bundle

第二個block進行測試。請注意我們重複使用了checkout和cache的代碼以將初始文件放入job中。最後一個命令用於啟動RSpec測試套件。

- name: Tests  task:    jobs:      - name: rspec        commands:          - checkout          - cache restore gems-$SEMAPHORE_GIT_BRANCH-$(checksum Gemfile.lock),gems-$SEMAPHORE_GIT_BRANCH,gems-master          - bundle install           - bundle exec rspec

最後一個部分我們來看看Promotion。Promotion能夠在一定條件下連接流水線以創建複雜的工作流程。所有job完成之後,我們使用 auto_promote_on來啟動下一個流水線。 

promotions:  - name: Dockerize    pipeline_file: docker-build.yml    auto_promote_on:      - result: passed

工作流程繼續執行下一個流水線。

我們可以在Kubernetes上運行任何東西,只要它打包在Docker鏡像中。在這一部分,我們將學習如何構建鏡像。

我們的Docker鏡像將包含應用程式的代碼、Ruby以及所有的庫。讓我們先來看一下Dockerfile:

FROM ruby:2.5 RUN apt-get update -qq && apt-get install -y build-essential ENV APP_HOME /appRUN mkdir $APP_HOMEWORKDIR $APP_HOME ADD Gemfile* $APP_HOME/RUN bundle install  ADD . $APP_HOME EXPOSE 4567 CMD ["bundle", "exec", "rackup", "--host", "0.0.0.0", "-p", "4567"]

Dockerfile就像一個詳細的菜譜,包含所有構建容器鏡像所需要的步驟和命令:

1、 從預構建的ruby鏡像開始

2、 使用apt-get安裝構建工具

3、 複製Gemfile,因為它具有所有的依賴項

4、 用bundle安裝它們

5、 複製app的原始碼

6、 定義監聽埠和啟動命令

我們將在Semaphore環境中bake我們的生產鏡像。然而,如果你想要在計算機上進行一個快速的測試,那麼請輸入:

$ docker build . -t test-image

使用Docker運行和暴露內部埠4567以在本地啟動伺服器:

$ docker run -p 4567:4567 test-image

你現在可以測試一個可用的HTTP端點:

$ curl -w "\n" localhost:4567hello world :))

Semaphore有一個安全的機制以存儲敏感信息,如密碼、令牌或密鑰等。為了能夠push鏡像到你的Docker Hub鏡像倉庫中,你需要使用你的用戶名和密碼來創建一個Secret:

打開你的Semaphore

在左側導航欄中,點擊【Secret

點擊【Creat New Secret

Secret的名字應該是Dockerhub,鍵入登錄信息(如下圖所示),並保存。

這個流水線開始構建並且push鏡像到Docker Hub,它僅僅有1個block和1個job:

這次,我們需要使用更好的性能,因為Docker往往更加耗費資源。我們選擇具有四個CPU,8GB RAM和35GB磁碟空間的中端機器e1-standard-4:

version: v1.0name: Docker buildagent:  machine:    type: e1-standard-4    os_image: ubuntu1804

構建block通過登錄到Docker Hub啟動,用戶名和密碼可以從我們剛創建的secret導入。登錄之後,Docker可以直接訪問鏡像倉庫。

下一個命令是docker pull,它試圖拉取最新鏡像。如果找到鏡像,那麼Docker可能能夠重新使用其中的一些層,以加速構建過程。如果沒有最新鏡像,也無需擔心,只是需要花費長一點的時間來構建。

最後,我們push新的鏡像。注意,這裡我們使用SEMAPHORE_WORKFLOW_ID 變量來標記鏡像。

blocks:  - name: Build    task:      secrets:        - name: dockerhub      jobs:      - name: Docker build        commands:          - echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin          - checkout          - docker pull "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest || true          - docker build --cache-from "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest -t "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID .          - docker images          - docker push "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID

當鏡像準備完畢,我們進入項目的交付階段。我們將用手動promotion來擴展我們的Semaphore 流水線。

promotions:  - name: Deploy to Kubernetes    pipeline_file: deploy-k8s.yml

要進行第一次自動構建,請進行push:

$ touch test-build$ git add test-build$ git commit -m "initial run on Semaphore「$ git push origin master

鏡像準備完成之後,我們就可以進入部署階段。

自動部署是Kubernetes的強項。我們所需要做的就是告訴集群我們最終的期望狀態,剩下的將由它來負責。

然而,在部署之前,你必須將kubeconfig文件上傳到Semaphore。

我們需要第二個secret:集群的kubeconfig。這個文件授予可以對它的管理訪問權限。因此,我們不希望將文件籤入存儲庫。

創建一個名為do-k8s的secret並且將kubeconfig文件上傳到/home/semaphore/.kube/dok8s.yaml中:

儘管Kubernetes已經是容器編排平臺,但是我們不直接管理容器。實際上,部署的最小單元是pod。一個pod就好像一群形影不離的朋友,總是一起去同一個地方。因此要保證在pod中的容器運行在同一個節點上並且有相同的IP。它們可以同步啟動和停止,並且由於它們在同一臺機器上運行,因此它們可以共享資源。

pod的問題在於它們可以隨時啟動和停止,我們沒辦法確定它們會被分配到的pod IP。要把用戶的http流量轉發,還需要提供一個公共IP和一個負載均衡器,它負責跟蹤pod和轉發客戶端的流量。

打開位於deploymente.yml的文件。這是一個部署我們應用程式的清單,它被3個dash分離成兩個資源。第一個,部署資源:

apiVersion: apps/v1kind: Deploymentmetadata:  name: semaphore-demo-ruby-kubernetesspec:  replicas: 1  selector:    matchLabels:      app: semaphore-demo-ruby-kubernetes  template:    metadata:      labels:        app: semaphore-demo-ruby-kubernetes    spec:      containers:        - name: semaphore-demo-ruby-kubernetes          image: $DOCKER_USERNAME/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID

這裡有幾個概念需要釐清:

第二個資源是服務。它綁定到埠80並且將HTTP流量轉發到部署中的pod:

--- apiVersion: v1kind: Servicemetadata:  name: semaphore-demo-ruby-kubernetes-lbspec:  selector:    app: semaphore-demo-ruby-kubernetes  type: LoadBalancer  ports:    - port: 80      targetPort: 4567

Kubernetes將selector與標籤相匹配以便將服務與pod連接起來。因此,我們在同一個集群中有許多服務和部署並且根據需要連接他們。

我們現在進入CI/CD配置的最後一個階段。這時,我們有一個定義在semaphore.yml的CI流水線,以及定義在docker-build.yml的Docker流水線。在這一步中,我們將部署到Kubernetes。

打開位於.semaphore/deploy-k8s.yml的部署流水線:

version: v1.0name: Deploy to Kubernetesagent:  machine:    type: e1-standard-2    os_image: ubuntu1804

兩個job組成最後的流水線:

Job 1開始部署。導入kubeconfig文件之後,envsubst將deployment.yaml中的佔位符變量替換為其實際值。然後,kubectl apply將清單發送到集群。

blocks:  - name: Deploy to Kubernetes    task:      secrets:        - name: do-k8s        - name: dockerhub       env_vars:        - name: KUBECONFIG          value: /home/semaphore/.kube/dok8s.yaml       jobs:      - name: Deploy        commands:          - checkout          - kubectl get nodes          - kubectl get pods          - envsubst < deployment.yml | tee deployment.yml          - kubectl apply -f deployment.yml

Job 2將鏡像標記為最新,以讓我們能夠在下一次運行中將其作為緩存使用。

- name: Tag latest release  task:    secrets:      - name: dockerhub    jobs:    - name: docker tag latest      commands:        - echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin        - docker pull "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID        - docker tag "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:$SEMAPHORE_WORKFLOW_ID "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest        - docker push "${DOCKER_USERNAME}"/semaphore-demo-ruby-kubernetes:latest

這是工作流程的最後一步了。

讓我們教我們的Sinatra應用程式唱歌。在app.rb中的App類中添加以下代碼:

get "/sing" do  "And now, the end is near   And so I face the final curtain..."end

推送修改的文件到Github:

$ git add .semaphore/*$ git add deployment.yml$ git add app.rb$ git commit -m "test deployment」$ git push origin master

等到docker構建流水線完成,你可以查看Semaphore的進度:

是時候進行部署了,點擊Promote按鈕,看它是否工作:

我們已經有了一個好的開始,現在就看Kubernetes的了。我們可以使用kubectl檢查部署狀態,初始狀態是三個所需的pod並且零可用:

$ kubectl get deploymentsNAME                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGEsemaphore-demo-ruby-kubernetes   3         0         0            0           15m

幾秒之後,pod已經啟動,reconciliation已經完成:

$ kubectl get deploymentsNAME                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGEsemaphore-demo-ruby-kubernetes   3         3         3            3           15m

使用get all獲得集群的通用狀態,它顯示了pod、服務、部署以及replica:

$ kubectl get allNAME                                                  READY   STATUS    RESTARTS   AGEpod/semaphore-demo-ruby-kubernetes-7d985f8b7c-454dh   1/1     Running   0          2mpod/semaphore-demo-ruby-kubernetes-7d985f8b7c-4pdqp   1/1     Running   0          119spod/semaphore-demo-ruby-kubernetes-7d985f8b7c-9wsgk   1/1     Running   0          2m34s  NAME                                        TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGEservice/kubernetes                          ClusterIP      10.12.0.1              443/TCP        24mservice/semaphore-demo-ruby-kubernetes-lb   LoadBalancer   10.12.15.50   35.232.70.45   80:31354/TCP   17m  NAME                                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGEdeployment.apps/semaphore-demo-ruby-kubernetes   3         3         3            3           17m NAME                                                        DESIRED   CURRENT   READY   AGEreplicaset.apps/semaphore-demo-ruby-kubernetes-7d985f8b7c   3         3         3       2m3

Service IP在pod之後展示。對於我來說,負載均衡器被分配到外部IP 35.232.70.45。需要將其更改為你的提供商分配給你的那個,然後我們來試試新的伺服器。

$ curl -w "\n" http://YOUR_EXTERNAL_IP/sing

現在,離結束已經不遠了。

當你使用了正確的CI/CD解決方案之後,部署到Kubernetes並不是那麼困難。你現在擁有一個Kubernetes的完全自動的持續交付流水線啦。

這裡有幾個建議可以讓你在Kubernetes上隨意fork並玩轉semaphore-demo-ruby-kubernetes:

創建一個staging集群  

構建一個部署容器並且在裡面運行測試

使用更多微服務擴展項目

相關焦點

  • 產後回診step by step!
    流程step by step  產後檢查項目及注意事項不少於產前檢查,茲將各項檢查內容一一介紹如下。  step1.測量體重  一般孕婦在孕期增加12~15公斤,產後2個月,體重應減少5~8公斤,一旦體重不減反增,就應適當調整飲食,多運動;反之,體重較孕前偏低的產婦,則應增加食量且注意營養的均衡攝取。
  • In "lockstep"?
    Lockstep, or lock step, is a term originally describing the way soldiers march in formation, you know, they way they raise each leg and arm in unison.
  • Step down
    和step相關的詞組還有很多,例如step across(訪問,看望);step for step(用同樣步調,並駕齊驅地);step out on sb.([美俚]在感情方面對某人不忠);It is the first step that costs.(萬事開頭難)等。 今年4月,麥當勞前任首席執行長吉姆·坎塔盧波心臟病突發去世,貝爾接掌帥印。
  • step-down
    step-down 文章
  • 短語「step up」
    提高;增加;走近1 It is time for the council to step up to theplate and provide the necessary leadership.2 We need to step up our marketing by improving the visuals and creating more relatable stories.我們市場宣傳要做得更好,主要要改進視覺設計、寫更能打動人的故事。
  • one step at a time是什麼意思呢? | 地道英語
    You need to take things one step at a time.別放棄,羅伯!你需要一步一步地做事情。 You mean walk - don't run?你是說走路,別跑? When you do things 'one step at a time', you improve them gradually in stages - step by step.當你「一步一步」做事情時,意思是逐步推進,一步一步來。
  • Step by step 冬季滑雪場完全徵服手冊
    Step by step冬季滑雪場完全徵服手冊  若計劃到韓國來趟滑雪之旅,請參考我們為您貼心準備的「Step by step,冬季滑雪場完全徵服手冊」  寫給新手的滑雪場指南  Step 1. 滑雪前的準備,租借滑雪裝備與購買吊椅券
  • 「The journey of a thousand miles begins with a single step.」
    To me, this quote means to take initiative and have courage to take that first step forward. So we see that without that first step, the journey to the goal will definitely not begin.
  • step-by-step: 夕小瑤版神經網絡調參指南
    在調參之前,小夕強烈建議在代碼裡完成下面幾件事:可視化訓練過程中每個step(batch)的loss。如果是分類任務,可以順便可視化出每個batch的準確率(不均衡數據可視化F1-score)。將訓練日誌在列印到屏幕上的同時也寫入到本地磁碟。如果能實時同步寫入那更好了(在python中可以用logging模塊可以輕鬆實現。
  • Step on your toes?
    If you analyze the situation, people who step on our toes are trying to land their feet on the ground where we’re standing.
  • step-by-step: 夕小瑤版神經網絡調參指南(上)
    在調參之前,小夕強烈建議在代碼裡完成下面幾件事:可視化訓練過程中每個step(batch)的loss。如果是分類任務,可以順便可視化出每個batch的準確率(不均衡數據可視化F1-score)。將訓練日誌在列印到屏幕上的同時也寫入到本地磁碟。如果能實時同步寫入那更好了(在python中可以用logging模塊可以輕鬆實現。
  • 「the first step is always the hardest」是什麼意思?
    the first step is always the hardest.萬事開頭難。The first step towards happinessis always the hardest.邁向幸福的第一步永遠是最困難的。
  • 髮型師step by step教你做!
    走近髮型師,還原他在後臺step by step的步驟。你會發現,那些看起來很複雜的髮型,其實操作起來並不難,難的其實是創意部分。還好我們不用為了漂亮髮型而想破腦袋,那些交給髮型師們去做吧,我們不妨跟隨Antonio Marras秀場髮型師Eugene Souleiman(威娜專業美發全球創意總監),來看看這款麻花辮是如何做到的!
  • 踩一腳油門是Step on it?
    step on it快一點Please step on it. I am going to be late.
  • 「梯子」是ladder,stepladder,stairs還是steps?
    Ladder vs. stepladder vs. stairs vs. steps這幾個詞有什麼區別呢?Ladder, stepladder, stairs and steps. What is the difference between these words?
  • Secession talk is a dangerous step
    Beijing yesterday slammed Taiwan leader Chen Shui-bian's intensified talk of independence, saying it was another "dangerous step" towards secession.
  • 雙語——「繼」寵物(A Step Pet)
    A Step Pet【譯】過繼的寵物【單詞】Step 原型:step 名詞 [step][step] n. 步驟;臺階;舞步;步伐 v.兼職地;部分時間地 part-"Now we have a step brother and a step pet!" they said.【譯】「現在我們有了一個繼兄弟和一個繼寵物!」他們說。【單詞】step 名詞 [step][step] n.
  • Kubernetes-應用部署問題定位和處理
    1、應用部署問題處理的整體思路在將容器化的應用部署到Kubernetes集群中,可能會出現各種問題。在本文中,以部署的高可用MySQL(請參考: Kubernetes-部署高可用的MySQL )為例展示如何進行問題定位和處理。另外為了能夠在Kubernetes集群外訪問MySQL資料庫,對外暴露了MySQL master的NodePort類型服務,服務名稱為mysql-0-svc。
  • 中國新說唱:吳亦凡讓我看到了他的step by step,請對他手下留情
    第一期只讓我記住了那個新疆的rapper,太多選手失誤,不明白他們是緊張了還是什麼,但是即使這個節目再不好,也讓我看到了並且重新認識了吳亦凡,他真的很棒,step by step。
  • One Step at a Time
    One step at a time, and that well placed,   We reach the grandest height;One stroke at a time, earth’s hidden stores   Will slowly come to light;One seed at a time,