iT邦幫忙

2021 iThome 鐵人賽

DAY 25
0
DevOps

關於我幫新公司建立整套部屬流程那檔事系列 第 25

EP25 - EKS 日誌蒐集使用 Loki 和 Grafana(一)

前四天我們經歷一番折騰,
終於把 Octopus Deploy 架起來,
從 Octopus Deploy 串好後,
整個 CI/CD 才算完整,
如果要佈置的環境有多個,
從 Dev、QA、SIT、UAT、Stage、Pre Production 最後到 Production,
而你又有多個專案時,
會開始發現 Octopus 幫我們解決很多問題,
但是 CI/CD 才算完整
並不表示做完,
我們還有日誌蒐集、監控還沒做,
目前為止,
我們的 AP 到 CI/CD 工具都沒有一個統一的介面,
可以查看日誌,
當然也別提日常備份,
那我們今天就要用一點時間將日誌蒐集做起來。

Helm

之前我們在做部署的時候
用了 kubectl 去執行 yaml 配置檔
但 k8s 還有一個更厲害的武器
那就是 Helm

Helm 是什麼?又解決什麼問題呢?
簡單來說就是可以將我們配置的這些 k8s yaml 檔模組化
而且還附帶版本控管
對於上新版或是回滾都相當方便
不用再次改 yaml

除了這些之外
還可以根據不同的環境
帶入參數之後
產生該環境所需要的 yaml 並進行部署

即使你都用不到這些
也可以使用它轉成 yaml 的功能
再使用 kubectl 執行這些轉換過後的 yaml 檔

接下來我們的例子不會用到這麼進階
會使用到 helm
只是單純因為使用它在 EKS 上安裝 Grafana 真的很方便而已

安裝 Helm

curl https://baltocdn.com/helm/signing.asc | sudo apt-key add -
sudo apt-get install apt-transport-https --yes
echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install helm

配置 EFS

蛤?都架設完陽春的 CI/CD
還有新的東西要設定?
其實這部分可要可不要
因為在建置 Grafana 的時候
它會自動要求一塊硬碟空間 (EBS)
來存放 Grafana 的一些設定
但是我們的 Grafana 是架設在 EKS 上
EKS 可能會隨機在不同的可用區域(AZ)建立 Node(EC2)
可是 EBS 是有綁 AZ
無法跨 AZ 存取
因此如果我們完全不改配置
萬一 Grafana crash
結果重啟在不同 AZ 的機械上
可能會無法讀取到原本設定而呈現初始化的狀態
為此我想使用 EFS 來解決這問題

什麼是 EFS

Amazon EFS 是一個簡單、無伺服器、一勞永逸的彈性檔案系統,可在 AWS 雲端中輕鬆設定、擴展和成本最佳化檔案儲存。只要在 AWS 管理主控台按幾下,就能建立 Amazon EC2 執行個體、Amazon 容器服務 (Amazon Elastic Container Service (ECS)、Amazon Elastic Kubernetes Service (EKS) 和 AWS Fargate) 以及 AWS Lambda 函數可透過檔案系統界面 (使用標準作業系統檔案 I/O API) 存取的檔案系統,而且該系統也支援完整的檔案系統存取語意 (例如,高一致性和檔案鎖定)。

Amazon EFS 檔案系統可將資料量從數 GB 自動擴展到數 PB,無須佈建儲存。數十個、數百個或甚至數千個運算執行個體可同時存取 Amazon EFS 檔案系統,而且 Amazon EFS 可為每個運算執行個體提供一致的效能。Amazon EFS 的設計目的是提供高耐用性和高可用性。使用 Amazon EFS,不需支付最低費用或設定成本,且您只需依使用量付費。

建立 EFS 所需的角色

取得供應商資訊

下 aws-cli 取得供應商資訊,等等會用到

aws eks describe-cluster --name aws-stage-cluster --query "cluster.identity.oidc.issuer" --output text

建立 IAM 政策和角色

resource "aws_iam_role" "amazon_eks_efs_csi_driverrole" {
    name = "AmazonEKS-EFS-CSI-DriverRole"
    path = "/"

    assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::[AWS 10 碼帳號]:oidc-provider/oidc.eks.ap-northeast-1.amazonaws.com/id/[填寫供應商相對應的資訊]"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "[供應商資訊]:sub": "system:serviceaccount:kube-system:efs-csi-controller-sa"
        }
      }
    }
  ]
}
EOF
}

resource "aws_iam_policy" "amazoneks_efs_csi_driver_policy" {
    name        = "AmazonEKS-EFS-CSI-Driver-Policy"
    path        = "/"
    description = ""

    policy = jsonencode({
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Action": [
              "elasticfilesystem:DescribeAccessPoints",
              "elasticfilesystem:DescribeFileSystems"
            ],
          "Resource": "*"
          },
          {
            "Effect": "Allow",
            "Action": [
              "elasticfilesystem:CreateAccessPoint"
            ],
            "Resource": "*",
            "Condition": {
              "StringLike": {
                "aws:RequestTag/efs.csi.aws.com/cluster": "true"
              }
            }
          },
          {
            "Effect": "Allow",
            "Action": "elasticfilesystem:DeleteAccessPoint",
            "Resource": "*",
            "Condition": {
              "StringEquals": {
                "aws:ResourceTag/efs.csi.aws.com/cluster": "true"
              }
            }
          }
        ]
    })
}

resource "aws_iam_role_policy_attachment" "amazoneks_efs" {
    role       = aws_iam_role.amazon_eks_efs_csi_driverrole.name
    policy_arn = aws_iam_policy.amazoneks_efs_csi_driver_policy.arn
}

新增 service account 並執行

efs-service-account.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: efs-csi-controller-sa
  namespace: kube-system
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/AmazonEKS-EFS-CSI-DriverRole

建立 EFS 供 EKS 使用

Terraform 新增 EFS

## EFS
resource "aws_efs_file_system" "grafana" {
    creation_token = "grafana"

    tags = {
        Name    = "grafana"
        Creator = "Terraform"
    }
}

resource "aws_efs_mount_target" "private_a" {
    file_system_id = aws_efs_file_system.grafana.id
    subnet_id      = aws_subnet.private_a.id
}

resource "aws_efs_mount_target" "private_c" {
    file_system_id = aws_efs_file_system.grafana.id
    subnet_id      = aws_subnet.private_c.id
}

resource "aws_efs_mount_target" "private_d" {
    file_system_id = aws_efs_file_system.grafana.id
    subnet_id      = aws_subnet.private_d.id
}
## EFS

建立完後
可以在 AWS Cloud Console 的 EFS 介面中看到
把 ID 記下來等等會用到
https://ithelp.ithome.com.tw/upload/images/20211007/201415180IEKWGiiJZ.png

點進去後
我們可以看到它掛載在不同的網段
每個網段上都可以使用
https://ithelp.ithome.com.tw/upload/images/20211007/20141518aXnVBKPhTl.png

下載資訊清單

kubectl kustomize \
    "github.com/kubernetes-sigs/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/ecr?ref=release-1.3" > driver.yaml

編輯檔案下載檔案

編輯檔案,並移除下列幾行建立 Kubernetes 服務帳戶。這不是必要的,因為服務帳戶是在上一個步驟中建立的。

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/name: aws-efs-csi-driver
  name: efs-csi-controller-sa
  namespace: kube-system
---

修改以下部分

尋找下列這一行。如果您的叢集不在us-west-2區域中,將下列位址取代為您所在地區的地址。完成變更後,請儲存修改後的資訊清單。

image: 602401143452.dkr.ecr.us-west-2.amazonaws.com/eks/aws-efs-csi-driver:v1.3.2
套用資訊清單。
kubectl apply -f driver.yaml

新增 StorageClass

  1. 下載StorageClass資訊清 EFS。
curl -o storageclass.yaml https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml
  1. 編輯檔案,取代fileSystemId使用您的檔案系統 ID。

  2. 部署儲存方案。

kubectl apply -f storageclass.yaml

建立 Storage

在空白處新增 pv.yaml 檔案
然後再 apply

pv.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: grafana

---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: efs-grafana-claim
  namespace: grafana
  labels:
    ss: efs-claim
  annotations:
    volume.beta.kubernetes.io/storage-class: "efs-sc"
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 20G

安裝 Grafana

下載 repo

sudo mkdir ~/helm
cd /tmp
helm pull grafana/loki-stack
sudo mv loki-stack-2.4.1.tgz ~/helm
cd ~/helm
sudo tar zxvf loki-stack-2.4.1.tgz

修改檔案

到 loki-stack 的 values.yaml 中
將 grafana 替換成以下資訊

grafana:
  enabled: true
  sidecar:
    datasources:
      enabled: true
  persistence:
    enabled: true
    type: pvc
    existingClaim: efs-grafana-claim
  image:
    tag: 7.5.0

安裝

helm install -f values.yaml grafana . --namespace=grafana

之後修改參數後
則需要將 install 改成 upgrade


今天我們配置了 Grafana 環境
並且還使用 efs
讓我們不需要而外擔心硬碟掛載的問題
但讀寫不頻繁才建議使用此方式
讀寫頻繁還是建議掛載 EBS
並修改 deployment 讓 Grafana 單獨運行在某個 az 的 EC2 上

明天我們將繼續進行
建好了 Grafana
其實整個套件中
Promtail 和 Loki 也有安裝
Promtail 幫我們自動蒐集 Log 並轉發到 Loki 中
雖然我們建立了 Grafana
但是目前我們還沒有配置 Ingress
所以現在還是看不到
這就是我們明天要繼續進行的部分
除了設置 Ingress
也要設定 Grafana 的 Dashboard 去查看這些資訊

參考資料:

  1. Installing Helm
  2. Amazon EFS 常見問答集
  3. Amazon EFS CSI 驅動程式
  4. Install Loki with Helm

上一篇
EP24 - 持續部署使用 Octopus Deploy 四部曲,整合 Jenkins 自動部署到 EKS
下一篇
EP26 - EKS 日誌蒐集使用 Loki 和 Grafana(二)
系列文
關於我幫新公司建立整套部屬流程那檔事30

尚未有邦友留言

立即登入留言