著名FinTech公司如何使用k3s+樹莓派在生產中構建輕量K8S裸機集羣

Boogie Software是歐洲著名的金融科技公司,多年來致力於爲銀行提供Fintech、AI、大數據高性能後端、移動應用程序、數據分析及UX等創新服務,幫助銀行推進數字化轉型。憑藉過去十多年在該領域的獨特經驗,Boogie已成爲數字銀行服務提供商中的領導者。本文做者是Boogie Software的資深軟件架構師Jari Tenhunen。他擁有超過15年的軟件開發經驗,擅長信息安全和網絡協議。而且長期管理項目和團隊,在其中主導軟件架構和技術,成功將多個產品推向市場。

Boogie Software的IT團隊在不少客戶銀行的核心銀行業務數字化的項目中使用到了Kubernetes和容器技術,所以咱們始終在想Kubernetes能如何使用更合適的硬件在本地工做。在本文中,我將詳細介紹咱們如何在樹莓派上構建輕量級裸機集羣,以在公司網絡中運行應用程序和服務。html

咱們之因此這麼作,有兩個緣由:第一,經過創建集羣,咱們將能夠擁有一個平臺,來可靠、靈活地運行公司網絡內部應用程序和服務;第二,咱們能夠經過此次機會學習更多關於Kubernetes、微服務以及容器的技能。若是你也想要參照咱們的經驗來構建一個類似的系統,我建議你至少要了解關於Docker容器、Kubernetes關鍵概念(節點、pod、服務、deployment等)以及IP網絡的基礎知識。node


硬件準備


你須要準備如下設備:git


  • 樹莓派2B/3B/3B+ 的型號,至少一個。你甚至在單個開發板上運行某些應用程序,可是建議使用兩個或更多的開發板來分散負載並增長冗餘。
  • 電源和可用於樹莓派的SD卡,現有的以太網交換機或空閒端口以及一些電纜。


在咱們的設置中,咱們目前有4個樹莓派3代B+開發板,因此在集羣中有一個master/server和3個代理節點。若是樹莓派有外殼固然更好,咱們的同事用3d打印機設計了一個。此外,機殼的背面有兩個用於冷卻的風扇,每一個開發板都位於一個托盤上,該托盤能夠熱插拔以進行維護。這些托盤前面還設有activity/heartbeat LED和電源開關的位置,它們都鏈接到開發板的GPIO接頭。web


軟件準備


對於Kubernetes的實現,咱們使用的是k3s。k3s是由Rancher Labs推出的一款輕量級、經過CNCF一致性認證的Kubernetes發行版。儘管這是一款剛推出不久的產品,但它真的十分穩定和易用,能夠實現秒級啓動。讓k3s從其餘輕量的Kubernetes發行版脫穎而出的緣由是,k3s可供生產使用,而諸如microk8s或Minikube之類的項目則沒法實現這一目的,而且k3s十分輕巧,還能夠在基於ARM的硬件上很好地運行。在k3s中,任何設備上安裝Kubernetes所需的一切都包含在這一個40MB的二進制文件當中。docker

k3s幾乎能在任何Linux發行版中很好地運行,所以咱們決定將Raspbian Stretch Lite做爲基礎OS,由於咱們不須要在開發板上添加任何額外的服務或者桌面UI。k3s確實須要在Linux內核中啓用cgroup,這能夠在Raspbian上經過向/boot/cmdline.txt:添加如下參數來實現:後端

cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
複製代碼


安裝k3s


k3s很是友好的地方在於,它能夠實現平滑安裝過程。你準備好你的server硬件以後,僅需幾分鐘就能夠完成設置,由於它僅需一行命令就能安裝server(主節點):api

curl -sfL https://get.k3s.io | sh -
複製代碼

代理節點也是如此:安全

curl -sfL https://get.k3s.io | K3S_TOKEN=<token_from_server> K3S_URL=https://<server_ip>:6443 sh -
複製代碼

其中token_from_server是來自服務器的文件/ var / lib / rancher / k3s / server / node-token的內容,server_ip是服務器節點的IP地址。至此,咱們的集羣已經啓動並正在運行,咱們能夠開始部署工做負載:bash

root@k3s-server:~# kubectl get nodes
NAME         STATUS   ROLES    AGE    VERSION
k3s-node1    Ready    <none>   40s    v1.13.4-k3s.1
k3s-server   Ready    <none>   108s   v1.13.4-k3s.1
複製代碼

爲了管理和監控集羣,咱們安裝了Kubernetes Dashboard,它可以提供給很是方便的web界面來查看整個系統的狀態、執行管理員操做並訪問日誌。同時,本地安裝和運行kubectl命令也很是有幫助,由於它可讓你從本身的計算機管理集羣,而無需ssh進入集羣。爲此,你只須要安裝kubectl,而後將集羣信息從服務器節點config /etc/rancher/k3s/k3s.yaml複製到本地kubeconfig文件中(一般是${HOME}/.kube/config)。服務器


使用負載均衡器暴露服務


默認狀況下,部署在Kubernetes集羣上的應用程序僅能夠在集羣中獲取(默認服務類型是ClusterIP)。若是想要從集羣外部獲取應用程序,有兩個選項。你可使用NodePort類型配置服務,該服務在靜態端口的每一個節點IP上暴露服務,你也可使用負載均衡器(服務類型LoadBalancer)。然而,NodePort服務有限制:它們使用本身專用的端口範圍,咱們只能經過端口號來區分應用。k3s內置了一個簡單的負載均衡器,但因爲它使用的是節點的IP地址,咱們可能很快就會用完IP/端口組合而且沒法將服務綁定到某個虛擬IP。基於這些緣由,咱們決定部署MetalLB——一種用於裸機集羣的負載均衡器實現。

只需應用YAML manifest便可安裝MetalLB。在現有網絡中運行MetalLB的最簡單方法是使用所謂的第2層模式,這意味着集羣節點經過ARP協議宣佈本地網絡中服務的虛擬IP。爲此,咱們從內部網絡保留了一小部分IP地址用於集羣服務。MetalLB的配置以下所示:

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: company-office
      protocol: layer2
      addresses:
      - 10.10.10.50-10.10.10.99
複製代碼

使用此配置,集羣服務將被暴露在範圍爲10.10.10.50—10.10.10.99的地址中。爲了綁定服務到指定的IP,你能夠在服務清單中使用loadBalancerIP參數:

apiVersion: v1
kind: Service
metadata:
  name: my-web-app
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  loadBalancerIP: 10.10.10.51
  selector:
    app: my-web-app
  type: LoadBalancer
複製代碼

在負載均衡中,咱們面臨諸多挑戰。例如,Kubernetes中限制在單個負載均衡器中同時使用TCP和UDP端口。要解決這一問題,你能夠定義兩個服務實例,一個用於TCP端口,另外一個用於UDP端口。其缺點是,除非啓用IP地址共享,不然你須要在不一樣的IP地址中運行這兩個服務。並且,因爲MetalLB是一個年輕項目,所以也存在一些小問題,但咱們相信這些很快都會獲得解決。


添加存儲


k3s暫時沒有內置的存儲解決方案,因此爲了使Pod可以訪問持久性文件存儲,咱們須要使用Kubernetes的插件來建立一個。因爲Kubernetes的目標之一是使應用程序與基礎架構解耦並使其可移植,所以Kubernetes中用PersistentVolume(PV)和PersistentVolumeClaim(PVC)的概念定義了用於存儲的抽象層。詳細的概念解釋能夠參照咱們以前發過的文章:詳解Kubernetes存儲關鍵概念。PV是一般由管理員配置並可供應用程序使用的存儲資源。另外一方面,PVC描述了應用程序對某種類型和必定數量的存儲的需求。建立PVC(一般做爲應用程序的一部分)時,若是有一個還沒有使用且知足應用程序PVC要求的可用PVC,它將綁定到PV。配置和維護全部這些須要手動工做,所以動態配置卷應運而生。

在咱們的基礎架構中,咱們已經有一個現有的NFS服務器,所以咱們決定將其用於集羣持久性文件存儲。在咱們的案例中,最簡單的方法是使用支持動態配置PV的NFS-Client Provisioner。Provisioner只需在現有的NFS共享上爲每一個新PV(集羣映射到PVC)上建立新目錄,而後將PV目錄掛載在使用它的容器中。這樣就無需配置NFS共享到單個pod中的卷,而是所有動態運行。


爲ARM交叉構建容器鏡像


顯然,在基於ARM的硬件上(如樹莓派)運行應用程序容器時,須要根據ARM的架構構建容器。在ARM架構容器中構建本身的應用程序時,可能會遇到一些陷阱。首先,基礎鏡像須要可用於你的目標架構體系。對於樹莓派3來講,一般須要使用arm32v7的基礎鏡像,它們能夠在大部分Docker鏡像倉庫中被調用。因此,當交叉構建應用程序時,確保你的Dockerfile包含如下代碼:

FROM arm32v7/alpine:latest
複製代碼

第二件須要注意的事是,你的主機Docker須要可以運行ARM二進制文件。若是你在mac上運行Docker,那操做將十分輕鬆,由於它對此有內置支持。若是是在Linux上,你須要執行一些步驟:

添加QEMU二進制文件到你的基礎鏡像

爲了在Linux上的Docker中運行ARM二進制文件,鏡像須要一個QEMU二進制文件。你能夠選擇一個已經包含了QEMU二進制文件的基礎鏡像,也能夠在鏡像構建過程當中複製

qemu-arm-static二進制文件到其中,例如,經過將如下行添加到你的Dockerfile中:

COPY --from=biarms/qemu-bin /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static
複製代碼
安全警示:請注意下載和運行未知的容器就如同下載和運行位置的.exe文件。除業餘項目外,其餘任何項目都應使用掃描/審覈過的鏡像(如Docker官方鏡像)或來自信任的組織和公司的容器鏡像。

而後,你須要在建立Docker鏡像的主機OS上註冊QEMU。這能夠簡單地經過如下方式實現:

docker run --rm --privileged multiarch/qemu-user-static:register --reset
複製代碼

能夠在構建實際鏡像以前將該命令添加到你的構建腳本中。總結一下,你的Dockerfile.arm應該看起來像這樣:

FROM arm32v7/alpine:latest
COPY --from=biarms/qemu-bin /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static
# commands to build your app go here…
# e.g. RUN apk add --update <pkgs that you need…>
複製代碼

而且你的build /CI腳本應該是:

docker run --rm --privileged multiarch/qemu-user-static:register --reset
docker build -t my-custom-image-arm . -f Dockerfile.arm
複製代碼

這將爲你提供ARM架構的容器鏡像。若是你對細節很感興趣,請參閱:

https://www.ecliptik.com/Cross-Building-and-Running-Multi-Arch-Docker-Images/

自動化構建和上傳到鏡像倉庫


最後一步是自動化整個流程,以便容器鏡像能夠自動構建而且自動上傳到一個鏡像倉庫,在那裏能夠輕鬆地將其部署到咱們地k3s集羣。在內部,咱們使用GitLab進行源代碼管理和CI/CD,所以咱們天然但願在其中運行這些構建,它甚至包括一個內置的容器鏡像倉庫,所以不須要設置單獨的鏡像倉庫。

關於構建Docker鏡像,GitLab有十分完善的文檔(https://docs.gitlab.com/ee/ci/docker/using_docker_build.html),所以咱們不在此贅述。在爲docker構建配置GitLab Runner以後,剩下要作的就是爲該項目建立.gitlab-ci.yml文件。在咱們的例子中,它看起來像這樣:

image: docker:stable
stages:
  - build
  - release
 
variables:
  DOCKER_DRIVER: overlay2
  CONTAINER_TEST_IMAGE: ${CI_REGISTRY_IMAGE}/${CI_PROJECT_NAME}-arm:${CI_COMMIT_REF_SLUG}
  CONTAINER_RELEASE_IMAGE: ${CI_REGISTRY_IMAGE}/${CI_PROJECT_NAME}-arm:latest
 
before_script:
- docker info
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
 
build_image:
  stage: build
  script:
    - docker pull $CONTAINER_RELEASE_IMAGE || true
    - docker run --rm --privileged multiarch/qemu-user-static:register --reset
    - docker build --cache-from $CONTAINER_RELEASE_IMAGE -t $CONTAINER_TEST_IMAGE . -f Dockerfile.arm
    - docker push $CONTAINER_TEST_IMAGE
 
release:
  stage: release
  script:
    - docker pull $CONTAINER_TEST_IMAGE
    - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
    - docker push $CONTAINER_RELEASE_IMAGE
複製代碼

既然在容器鏡像倉庫中咱們有了咱們的鏡像,咱們只須要將它們部署到咱們的集羣中。爲了授予集羣訪問鏡像倉庫的權限,咱們在GitLab中建立了一個deploy令牌,而後將令牌憑據做爲docker-registry 密鑰添加到集羣中:

kubectl create secret docker-registry deploycred --docker-server=<your-registry-server> --docker-username=<token-username> --docker-password=<token-password> --docker-email=<your-email>
複製代碼

以後,能夠在YAML文件PodSpec中使用deploy 令牌密鑰:

imagePullSecrets:
      - name: deploycred
     containers:
      - name: myapp
        image: gitlab.mycompany.com:4567/my/project/my-app-arm:latest
複製代碼

完成全部這些步驟以後,咱們終於擁有了一個從私有鏡像倉庫中的源代碼到ARM容器鏡像的自動CI / CD流水線,能夠將其部署到集羣中。

結 語


總而言之,事實證實,創建和運行本身的裸機Kubernetes集羣比預期的要容易。並且k3s確實是在邊緣計算場景中和通常配置較低的硬件上運行容器化服務的明智選擇。

一個小缺點是k3s尚不支持高可用(多主設備配置)。儘管單個主服務器設置已經具備至關的彈性,由於即便主服務器離線,服務仍可在代理節點上繼續運行,咱們仍是但願爲主節點提供一些冗餘。顯然,此功能正在開發中,但在此功能可用以前,咱們建議從服務器節點配置中進行備份。

相關文章
相關標籤/搜索