연습 - Kubernetes를 사용하여 인프라 복원력 구현

완료됨

이전 단원에서는 .NET 네이티브 복원력 확장을 사용하여 오류 처리 코드를 추가하여 복원력을 구현했습니다. 그러나 이 변경은 변경한 서비스에만 적용됩니다. 많은 서비스가 포함된 대규모 앱을 업데이트하는 것은 간단하지 않습니다.

이 단원에서는 코드 기반 복원력을 사용하는 대신 인프라 기반 복원력이라는 전체 앱에 걸쳐 있는 접근 방식을 사용합니다. 다음을 수행합니다.

  • 복원력 없이 앱을 Kubernetes에 다시 배포합니다.
  • Kubernetes 클러스터에 Linkerd를 배포합니다.
  • 복원력을 위해 Linkerd를 사용하도록 앱을 구성합니다.
  • Linkerd를 사용하여 앱 동작을 탐색합니다.

앱 다시 배포

Linkerd를 적용하기 전에 먼저 앱 상태를 코드 기반 복원력이 추가되기 전으로 되돌립니다. 되돌리려면 다음 단계를 수행합니다.

  1. 아래쪽 패널에서 터미널 탭을 선택하고 다음 git 명령을 실행하여 변경 내용을 실행 취소합니다.

    cd Store
    git checkout Program.cs
    git checkout Store.csproj
    cd ..
    dotnet publish /p:PublishProfile=DefaultContainer
    

Kubernetes 설치

코드스페이스에서 Kubernetes 및 k3d를 설치합니다. k3d는 로컬 컴퓨터의 VM(Virtual Machine) 내에서 단일 노드 Kubernetes 클러스터를 실행하는 도구입니다. Kubernetes 배포를 로컬로 테스트하는 데 유용하며 codespace 내에서 잘 실행됩니다.

다음 명령을 실행하여 Kubernetes 및 MiniKube를 설치합니다.

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/kubernetes-apt-keyring.gpg

echo 'deb [signed-by=/etc/apt/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update
sudo apt-get install -y kubectl

curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
k3d cluster create devcluster --config k3d.yml

Docker 허브에 eShop 서비스 배포

빌드하는 서비스의 로컬 이미지는 Kubernetes에 배포할 수 있도록 컨테이너 레지스트리에 호스트되어야 합니다. 이 단원에서는 Docker 허브를 컨테이너 레지스트리로 사용합니다.

다음 명령을 실행하여 이미지를 Docker Hub에 푸시합니다.

sudo docker login

sudo docker tag products [your username]/productservice
sudo docker tag store [your username]/storeimage

sudo docker push [your username]/productservice
sudo docker push [your username]/storeimage

docker-compose 파일을 Kubernetes 매니페스트로 변환

현재 Docker에서 앱이 실행되는 방식을 정의합니다. Kubernetes는 앱 실행 방법을 정의하기 위해 다른 형식을 사용합니다. Kompose라는 도구를 사용하여 docker-compose 파일을 Kubernetes 매니페스트로 변환할 수 있습니다.

  1. Docker Hub에 푸시한 이미지를 사용하려면 이러한 파일을 편집해야 합니다.

  2. codespace에서 backend-deploy.yml 파일을 엽니다.

  3. 이 줄을 변경합니다.

      containers:
        - image: [YOUR DOCKER USER NAME]/productservice:latest
    

    자리 표시자 [YOUR DOCKER USER NAME]을 실제 Docker 사용자 이름으로 바꿉니다.

  4. frontend-deploy.yml 파일에 대해 다음 단계를 반복합니다.

  5. 이 줄을 변경합니다.

      containers:
      - name: storefrontend
        image: [YOUR DOCKER USER NAME]/storeimage:latest  
    

    자리 표시자 [YOUR DOCKER USER NAME]을 실제 Docker 사용자 이름으로 바꿉니다.

  6. Kubernetes에 eShop 앱을 배포합니다.

    kubectl apply -f backend-deploy.yml,frontend-deploy.yml  
    

    다음 메시지와 유사한 출력이 표시됩니다.

    deployment.apps/productsbackend created
    service/productsbackend created
    deployment.apps/storefrontend created
    service/storefrontend created
    
  7. 모든 서비스가 실행되고 있는지 확인합니다.

    kubectl get pods
    

    다음 메시지와 유사한 출력이 표시됩니다.

    NAME                        READY   STATUS    RESTARTS   AGE
    backend-66f5657758-5gnkw    1/1     Running   0          20s
    frontend-5c9d8dbf5f-tp456   1/1     Running   0          20s
    
  8. 포트 탭으로 전환하여 Kubernetes에서 실행되는 eShop을 보려면 프런트 엔드(32000) 포트 옆에 있는 지구본 아이콘을 선택합니다.

Linkerd 설치

개발 컨테이너는 Linkerd CLI를 설치해야 합니다. 다음 명령을 실행하여 Linkerd 필수 구성 요소가 충족되는지 확인합니다.

curl -sL run.linkerd.io/install | sh
export PATH=$PATH:/home/vscode/.linkerd2/bin
linkerd check --pre

다음과 유사한 출력이 표시됩니다.

kubernetes-api
--------------
√ can initialize the client
√ can query the Kubernetes API

kubernetes-version
------------------
√ is running the minimum Kubernetes API version
√ is running the minimum kubectl version

pre-kubernetes-setup
--------------------
√ control plane namespace does not already exist
√ can create non-namespaced resources
√ can create ServiceAccounts
√ can create Services
√ can create Deployments
√ can create CronJobs
√ can create ConfigMaps
√ can create Secrets
√ can read Secrets
√ can read extension-apiserver-authentication configmap
√ no clock skew detected

pre-kubernetes-capability
-------------------------
√ has NET_ADMIN capability
√ has NET_RAW capability

linkerd-version
---------------
√ can determine the latest version
√ cli is up-to-date

Status check results are √

Kubernetes에 Linkerd 배포

먼저 다음 명령을 실행하여 CRD(사용자 지정 리소스 정의)를 설치합니다.

linkerd install --crds | kubectl apply -f -

그런 후 다음 명령을 실행합니다.

linkerd install --set proxyInit.runAsRoot=true | kubectl apply -f -

위의 명령은 다음을 수행합니다.

  • linkerd install은 필요한 컨트롤 플레인 리소스를 사용하여 Kubernetes 매니페스트를 생성합니다.
  • 생성된 매니페스트는 kubectl apply로 파이프되어 Kubernetes 클러스터에 컨트롤 플레인 리소스를 설치합니다.

출력의 첫 번째 줄은 컨트롤 플레인이 고유 linkerd 네임스페이스에 설치되었음을 보여 줍니다. 나머지 출력은 생성되는 개체를 나타냅니다.

namespace/linkerd created
clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-identity created
clusterrolebinding.rbac.authorization.k8s.io/linkerd-linkerd-identity created
serviceaccount/linkerd-identity created
clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-controller created

Linkerd 배포 유효성 검사

다음 명령을 실행합니다.

linkerd check

위의 명령은 Linkerd CLI 및 컨트롤 플레인의 구성을 분석합니다. Linkerd가 올바르게 구성된 경우 다음과 같은 출력이 표시됩니다.

kubernetes-api
--------------
√ can initialize the client
√ can query the Kubernetes API

kubernetes-version
------------------
√ is running the minimum Kubernetes API version
√ is running the minimum kubectl version

linkerd-existence
-----------------
√ 'linkerd-config' config map exists
√ heartbeat ServiceAccount exist
√ control plane replica sets are ready
√ no unschedulable pods
√ controller pod is running
√ can initialize the client
√ can query the control plane API

linkerd-config
--------------
√ control plane Namespace exists
√ control plane ClusterRoles exist
√ control plane ClusterRoleBindings exist
√ control plane ServiceAccounts exist
√ control plane CustomResourceDefinitions exist
√ control plane MutatingWebhookConfigurations exist
√ control plane ValidatingWebhookConfigurations exist
√ control plane PodSecurityPolicies exist

linkerd-identity
----------------
√ certificate config is valid
√ trust anchors are using supported crypto algorithm
√ trust anchors are within their validity period
√ trust anchors are valid for at least 60 days
√ issuer cert is using supported crypto algorithm
√ issuer cert is within its validity period
√ issuer cert is valid for at least 60 days
√ issuer cert is issued by the trust anchor

linkerd-api
-----------
√ control plane pods are ready
√ control plane self-check
√ [kubernetes] control plane can talk to Kubernetes
√ [prometheus] control plane can talk to Prometheus
√ tap api service is running

linkerd-version
---------------
√ can determine the latest version
√ CLI is up to date

control-plane-version
---------------------
√ control plane is up to date
√ control plane and CLI versions match

linkerd-addons
--------------
√ 'linkerd-config-addons' config map exists

linkerd-grafana
---------------
√ grafana add-on service account exists
√ grafana add-on config map exists
√ grafana pod is running

Status check results are √

설치된 Linkerd 구성 요소 목록을 보려면 kubectl -n linkerd get deploy 명령을 실행합니다.

Linkerd를 사용하도록 앱 구성

링커드는 배포되었지만 구성되지 않았습니다. 앱의 동작은 변경되지 않습니다.

Linkerd는 서비스 내부를 인식하지 못하고 오류가 발생한 요청을 다시 시도하는 것이 적절한지 여부를 확인할 수 없습니다. 예를 들어 오류가 발생한 HTTP POST를 결제에 다시 시도하는 것은 좋지 않은 생각입니다. 이러한 이유로 서비스 프로필이 필요합니다. ‘서비스 프로필’은 서비스의 경로를 정의하는 사용자 지정 Kubernetes 리소스입니다. 또한 재시도 및 시간 제한과 같은 경로별 기능을 사용하도록 설정합니다. Linkerd는 서비스 프로필 매니페스트에 구성된 경로만 다시 시도합니다.

간단히 하기 위해 집계 서비스와 쿠폰 서비스에만 Linkerd를 구현합니다. 이러한 두 서비스에 대해 Linkerd를 구현하려면 다음을 수행합니다.

  • Linkerd가 Pod에 프록시 컨테이너를 만들도록 eShop 배포를 수정합니다.
  • 쿠폰 서비스의 경로에 대한 재시도를 구성하려면 클러스터에 서비스 프로필 개체를 추가합니다.

eShop 배포 수정

Linkerd 프록시 컨테이너를 사용하도록 서비스를 구성해야 합니다.

  1. 템플릿 메타데이터에서 backend-deploy.yml 파일에 linkerd.io/inject: enabled 주석을 추가합니다.

      template:
        metadata:
          annotations:
            linkerd.io/inject: enabled
          labels: 
    
  2. 같은 위치에 있는 linkerd.io/inject: enabledfrontend-deploy.yml 파일에 주석을 추가합니다.

  3. Kubernetes 클러스터에서 배포를 업데이트합니다.

    kubectl apply -f backend-deploy.yml,frontend-deploy.yml
    

제품 서비스에 Linkerd 서비스 프로필 적용

제품 서비스에 대한 서비스 프로필 매니페스트는 다음과 같습니다.

apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
  name: backend
  namespace: default
spec:
  routes:
  - condition:
      method: GET
      pathRegex: /api/Product
    name: GET /v1/products
    isRetryable: true
  retryBudget:
    retryRatio: 0.2
    minRetriesPerSecond: 10
    ttl: 120s

위의 매니페스트는 다음과 같이 구성됩니다.

  • /api/Product 패턴과 일치하는 idempotent HTTP GET 경로를 다시 시도할 수 있습니다.
  • 재시도는 요청 로드에 추가 20% 이하 및 추가로 초당 10개의 “무료” 재시도를 추가할 수 있습니다.

다음 명령을 실행하여 Kubernetes 클러스터의 서비스 프로필을 사용합니다.

kubectl apply -f - <<EOF
apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
  name: backend
  namespace: default
spec:
  routes:
  - condition:
      method: GET
      pathRegex: /api/Product
    name: GET /v1/products 
    isRetryable: true
  retryBudget:
    retryRatio: 0.2
    minRetriesPerSecond: 10
    ttl: 120s  
EOF

다음과 같은 출력이 표시됩니다.

serviceprofile.linkerd.io/backend created

서비스 메시에 모니터링 설치

링커드에는 추가 기능을 제공하는 확장이 있습니다. viz 확장을 설치하고 Linkerd의 대시보드에서 앱의 상태를 확인합니다.

  1. 터미널에서 다음 명령을 실행하여 확장을 설치합니다.

    linkerd viz install | kubectl apply -f -
    
  2. 다음 명령을 사용하여 대시보드를 봅니다.

    linkerd viz dashboard
    

    트 탭으로 이동하여 링커드 비주얼리제이션 대시보드 실행 프로세스와 함께 전달된 새 포트를 확인합니다. 브라우저에서 열기를 선택하여 대시보드를 엽니다.

  3. Linkerd 대시보드에서 네임스페이스를 선택합니다.

  4. HTTP 메트릭에서 기본값을 선택합니다.

    Screenshot showing the Linkerd dashboard with both the frontend and backend.

Linkerd 복원력 테스트

재배포된 컨테이너가 정상 상태이면 다음 단계에 따라 Linkerd를 사용하여 앱의 동작을 테스트합니다.

  1. 다음 명령을 사용하여 실행 중인 Pod의 상태를 확인합니다.

    kubectl get pods --all-namespaces
    
  2. 모든 제품 서비스 Pod를 중지합니다.

    kubectl scale deployment productsbackend --replicas=0
    
  3. eShop 웹앱으로 이동하여 제품을 확인합니다. "제품을 로드하는 데 문제가 있습니다"라는 오류 메시지가 표시될 때까지 지연이 발생할 수 있습니다. 나중에 다시 시도하세요."

  4. 제품 서비스 Pod를 다시 시작합니다.

    kubectl scale deployment productsbackend --replicas=1
    
  5. 이제 앱에 제품이 표시됩니다.

Linkerd는 코드 기반 복원력과는 다른 복원력 접근 방식을 따릅니다. Linkerd는 빠르게 연속해서 작업을 여러 번 다시 시도했습니다. 이 동작을 지원하기 위해 앱을 변경할 필요가 없었습니다.

추가 정보

Linkerd 구성에 대한 자세한 내용은 다음 리소스를 참조하세요.