經過K3S與Github Action部署一個Hexo博客

最近看上了一個Hexo博客的主題,就打算本身也開一個博客。驚奇的發現 github 上竟然已經有了 CI 功能(是我火星了)。因而乎,一個經過 GitHub Actions 持續部署博客到 Kubernetes 中的想法就出現了。經過這種方式,咱們能夠實現 0 停機時間更新 Hexo、彈性擴縮、健康檢查和故障轉移等等。。。不過其實都沒啥意義,一個博客而已,跑在 1c1g 的機器上,不必引入這種重型工具。html

但這架不住我閒得慌,也就有了如今這一篇記錄。本文基本是純記錄,對於不少事情不會有太多介紹和解釋。node

事前準備

  • 一個 Github 帳號
  • 一個已經配置好的 hexo 博客。這方面教程太多了,不贅述了
  • 一個雲主機,配置無所謂
  • 必定的 Linux 操做知識
  • 經得住折騰

部署Kubernetes?仍是K3s吧

最後我仍是沒有使用 Kubernetes,而是轉爲使用了K3s。緣由很簡單,Kubernetes 他實在是太大了,光是一個 Etcd 就夠我這個可憐的 1c1g 主機喝一壺了。雖然 K8s(Kubernetes)多是不能用了,但咱們還有 K3s 啊。mysql

啥是K3s

K3s是 Rancher Lab 在 18 年 7 月發行的一個基於 K8s 的容器編排工具。雖然在使用上和 K8s 幾乎如出一轍,可是爲了減小資源的使用,k3s 刪除了不少雲服務相關的插件( Cloud Provider)和存儲插件。同時,k3s 使用 sqlite 做爲默認的數據庫,這能夠進一步減小 k3s 的資源使用率,對於單機部署來講天然是極好的。固然,k3s 也支持配置 etcd 以及其餘數據庫,如 mysql、postgresql。nginx

就在這幾天(2020 年 1 月 13 號),k3s 正式 release 了 1.0 版本。這意味着 K3S 已經能夠正常的使用了。因此我也是第一時間的在本身的雲主機上部署了一套來玩。不過值得一提的是,k3s 中的容器並不是是使用 docker 來運行的,而是使用了containderd,這個工具經過crictl交互,子命令和 docker 都差很少。若是想要使用 docker 做爲 container runtime,須要在啓動參數中指定。git

在服務器中安裝K3s

腳本安裝

一般狀況下,咱們只須要運行一行curl -sfL https://get.k3s.io | sh -就能夠完成 K3s 的安裝了。github

手動安裝K3S

假如咱們不幸遇到了一些網絡問題,沒法順利的下載 k3s 二進制文件的話。那麼咱們能夠如今 k3s 的release頁面中找到本身須要的版本,並想辦法把它下載下來。sql

下載下來之後,咱們進入到文件所在的目錄,並經過 scp 命令,將這個文件上傳到咱們的機器中。docker

# windows中可能須要先開啓openssh功能,若是不能開啓openssh的話,咱們能夠安裝git bash來運行這個命令
scp k3s root@xxx.xxx.xxx

上傳完後,登陸到咱們的主機中,咱們須要爲其賦予啓動權限,並將 K3S 移動到/usr/local/bin數據庫

# 爲k3s賦予可執行權限
chmod +x k3s
# 移動文件到/usr/local/bin中
mv k3s /usr/local/bin
# 後臺運行k3s,這樣啓動k3s會使用默認的配置,更多配置請看https://rancher.com/docs/k3s/latest/en/installation/install-options/
(k3s server &)

安裝完成後,咱們能夠經過一下命令來判斷安裝是否成功。npm

# 腳本安裝的能夠用這個指令
kubectl get all
# 或
k3s kubectl get all

在安裝完後,可能仍是沒法從外網訪問這個 K3s,這時候要看一下 iptables 或者其餘防火牆設置。對於阿里雲、騰訊雲之類的雲主機,咱們還須要更改安全組設置,容許 6443 端口的入向流量進入。

Action 你的博客

在 K3s 安裝完成後,咱們就能夠開始準備將 Hexo 博客的 github 項目佈置上 Github Actions 了。Github Actions 是由 Github 官方提供的一套 CI 方案,對於 CI 不太瞭解的,能夠看看阮一峯的介紹。總之,經過 Actions,咱們能夠在每次提交代碼的時候,讓 GitHub 自動幫咱們完成編譯->打包->測試->部署的整個過程。Actions 能作的操做很是的多,詳細的說明也能夠參考阮一峯的博客

如下是本博客的 Actions 配置,這個配置只會在 master 收到 push 時觸發。隨後會使用hexo-cli將博客編譯成靜態文件;再將這些靜態文件打包到一個 docker 鏡像中,並 push 到個人鏡像倉庫;最後經過 kubectl 將個人應用配置部署到 k3s 服務上。只須要將這個 yaml 文件放在項目根目錄下的.github/workflows文件夾中,再 push 到 GitHub 上,咱們的配置就會生效了。

name: master
on:
  push:
      branches:
      - master
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    # node 編譯
    - name: build
      uses: actions/setup-node@v1
    - run: |
        npm i -g hexo-cli
        npm i
        hexo clean
        hexo g
    # docker build,並push
    - name: Docker push
      uses: azure/docker-login@v1
      with:
        login-server: reg.qiniu.com
        username: ${{ secrets.REGISTRY_USERNAME }}
        password: ${{ secrets.REGISTRY_PASSWORD }}
    - run: |
        docker build -t reg.qiniu.com/holo-blog/blog:${{ github.sha }} -t reg.qiniu.com/holo-blog/blog .
        docker push reg.qiniu.com/holo-blog/blog:${{ github.sha }}
        docker push reg.qiniu.com/holo-blog/blog
    # 讓K8s應用deployment
    - run: |
        sed -i 's/{TAG}/${{ github.sha }}/g' deployment.yaml
    - name: deploy to cluster
      uses: steebchen/kubectl@master
      env:
        KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_DATA }}
        KUBECTL_VERSION: "1.15"
      with:
        args: apply -f deployment.yaml
    - name: verify deployment
      uses: steebchen/kubectl@master
      env:
        KUBE_CONFIG_DATA: ${{ secrets.KUBE_CONFIG_DATA }}
        KUBECTL_VERSION: "1.15"
      with:
        args: '"rollout status -n blog deployment/blog"'

在這個配置中咱們使用到了三個 secrets,分別是鏡像倉帳號密碼和 kubeconfig,經過 secrets 調用敏感信息能夠避免在 actions 日誌或者代碼倉庫中將這部分信息暴露出來。咱們能夠在 GitHub 項目settings-secrets頁面中設置 secrets。KUBE_CONFIG_DATA這個密鑰是 kubeconfig 文件的 base64 版,咱們能夠經過如下命令來獲得這個 secrets。

kubectl config view | base64
# 或
k3s kubectl config view | base64

經過這種方式獲得的 kubeconfig 中的 apiserver 的地址可能不正確(是 127.0.0.1),咱們能夠先將 kubeconfig 保存成文件,在修改完成後在經過cat kubeconfig | base64獲得正確的 config 信息。

Docker打包與推送

Docker push這一步中,會用到根目錄的一個 dockerfile 文件。經過 dockerfile,咱們能夠將應用部署到任意同架構同系統的機器中。關於dockerdockerfile的更多信息能夠查看官方文檔。

對於 hexo 博客而言,經過hexo g編譯成靜態文件後咱們就能夠直接經過訪問public文件夾中的 index.html 文件來預覽咱們的博客了。因此在這裏咱們能夠經過將靜態文件打包到一個 nginx 鏡像中,並暴露 80 端口來爲提供 http 請求提供服務。

FROM nginx:1.17.7-alpine
EXPOSE 80
EXPOSE 443
COPY public /usr/share/nginx/html

打包好鏡像後,咱們須要將其 push 到某一個鏡像倉庫中,我用的是七牛雲,由於不要錢。

Apply你的升級!

最後,咱們須要通知 k3s 部署服務或者升級服務。經過在設置好 kubeconfig 文件,咱們便能使用 kubectl 遠程訪問 apiserver。在經過kubectl apply -f deployment.yaml部署上最新的配置文件便可。

在這裏我又偷了點懶,應用的文件名雖然叫作deployment.yaml,可是其實serviceingress的配置我也一併寫入其中了,其完整配置以下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: blog
  namespace: blog
spec:
  rules:
  - host: dalaocarryme.com
    http:
      paths:
      - backend:
          serviceName: blog
          servicePort: 80
  - host: www.dalaocarryme.com
    http:
      paths:
      - backend:
          serviceName: blog
          servicePort: 80
  - host: blog.dalaocarryme.com
    http:
      paths:
      - backend:
          serviceName: blog
          servicePort: 80
  backend:
    serviceName: blog
    servicePort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: blog
  namespace: blog
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: blog
  sessionAffinity: ClientIP
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: blog
  namespace: blog
spec:
  progressDeadlineSeconds: 600
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: blog
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: blog
    spec:
      containers:
      - image: reg.qiniu.com/holo-blog/blog:{TAG}
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 80
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 2
          successThreshold: 1
          timeoutSeconds: 2
        name: blog
        ports:
        - containerPort: 80
          name: 80tcp02
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 80
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 2
          successThreshold: 2
          timeoutSeconds: 2
        resources: {}
        securityContext:
          allowPrivilegeEscalation: false
          capabilities: {}
          privileged: false
          readOnlyRootFilesystem: false
          runAsNonRoot: false
        stdin: true
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        tty: true
        volumeMounts:
        - mountPath: /usr/share/nginx/html/db.json
          name: db
        - mountPath: /usr/share/nginx/html/Thumbs.json
          name: thumbs
      dnsConfig: {}
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      volumes:
      - hostPath:
          path: /data/db.json
          type: ""
        name: db
      - hostPath:
          path: /data/Thumbs.json
          type: ""
        name: thumbs

須要注意的是,在 docker build 時,我是用的 gitsha 來給鏡像打的 tag,因此在 deployment 對象中,個人鏡像 tag 那個留的是一個{TAG}佔位符。而後咱們再用 sed 命令將這個佔位符替換爲 gitsha 便可。在 actions 中配置以下:

- run: |
        sed -i 's/{TAG}/${{ github.sha }}/g' deployment.yaml

對於 hexo 中的點擊數據點贊數據,咱們能夠經過掛載一個本地捲來將其持久化。這樣咱們的鏡像更新就不會將咱們的數據帶走了。

若是但願可以 0 中斷更新,咱們能夠部署兩個 pod,或者部署 1 個 pod,可是將更新策略設置爲 0 個maxUnavailable,這樣就能夠始終保證有一個 pod 在提供服務了。

其餘還有不少細節須要注意,但在這裏就很少作展開了。將來可能會作一系列關於 kubernetes 和 git 的文章,感興趣能夠關注如下。

本文中所用到的設置與代碼都在 https://github.com/Okabe-Kuri... 中。

相關文章
相關標籤/搜索