GithubアクションでKubernetesに継続的に展開.


背景


我々はGoogleのクラウドプラットフォーム上の若いベルリンベースのスタートアップです.GCPは、以前の企業で使用していた他のクラウドプロバイダと比較して、はるかに開発者フレンドリーであることがわかります.Google Cloudは、gcloud、プラットフォーム上でクラウドリソースをやり取りし、管理するために使用できるCLIツールを提供しています.これは、dockerkubectlのような様々な他のツールの資格情報を認可し、構成するために使用することができます.GCPは、適切なIAM許可を割り当てることによってサービスを管理するのに使用できるService-Accountsの概念を持っています.

なぜGithubアクション?


前の会社のSRE/DEVOPS/Platformチームの最大の痛み点の1つは、CI/CD仕事を走らせているJenkinsクラスタを管理していました.典型的なセルフマネージインストールには、次の課題があります.
  • 自動スケーリングのニーズの日.あなたは、コアビジネス時間中に仕事をすぐに実行し、それ以外の容量を削減する能力を増加する必要があります.
  • ジョブは、インストールされたソフトウェアの異なるバージョンを必要とするかもしれない.例- 1つのサービスがJava 11を必要とするかもしれません、そして、他のサービスはすでにJava 15を適応させたかもしれません.
  • 同じ共有ワーカーのノードで動作しているジョブが適切に分離されていない場合、同じファイルやライブラリに依存し、それらを上書きすることによって相互に干渉することができます.
  • 同じ労働者ノードで動いている
  • 仕事は、ビルド時間の増加につながるリソースのために競争することができます、あるいは、時々、タイムアウトはパイプラインの中でflakinessを引き起こします.
  • メインサーバと労働者ノードの一定のソフトウェアメンテナンス.これは、ベースOSのアップグレード、パッチ、または手動でインストールされているソフトウェアを更新が含まれます.
  • 我々がプラットホームのアーキテクチャについて議論していたとき、関係者は過去に彼らが持っていたCDサーバで彼らの(辛い)経験を起こしました.私たちは皆、私たち自身のCI/CDサーバクラスタを管理したくなかったことに同意しました.
    上記のすべての問題を解決するために、いくつかの理由のために、我々はGithub Actions

    GitHubアクションは、YAMLベースのシンタックスを提供して、ジョブの設定を行います.
    我々は、継続的に統合、ビルド&テストするには、単純な仕事を持って開始し、コンテナのレジストリにプッシュチェッカーコンテナ&プッシュを作成します.pushサービスからのサンプルです.
    on:
      push:
        branches:
          - master
    
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v2 # checkout repo
          - uses: actions/setup-java@v1 # Set up latest Java 14
            with:
              java-version: 14
    
          - name: Build with Gradle
            run: ./gradlew clean build
    
          - uses: GoogleCloudPlatform/github-actions/setup-gcloud@master # Setup gcloud
            with:
              service_account_key: ${{ secrets.GCP_SA_KEY }} # ServiceAccount key with necessary rights added as a secret on Github.
    
            # Configure credentials for docker
          - run: gcloud auth configure-docker
    
            # Build the Docker image
          - run: docker build -t gcr.io/example.com/${{ github.event.repository.name }}:${{ github.sha }} .
    
            # Push the Docker image to Google Container Registry
          - run: docker push gcr.io/example.com/${{ github.event.repository.name }}:${{ github.sha }}
    

    GKE上でのアプリケーションの配備


    アーキテクチャのもう一つの重要な部分は、サービスが展開される我々のKubernetesクラスタです.私たちは誇らしげにGoogle Kubernetes Engineを使用しており、これまでの経験を管理し、スケールし、操作上のオーバーヘッドを除去する簡単です肯定的です.
    Kibernetesはmergeで管理されており、java CLIは必要なkubeconfigを生成することによって資格情報を設定するために使用できます.
    アプリケーションはHelmチャートとしてパッケージ化され、環境に応じて設定されます.kubectlがクラスタと対話するためにgcloudを利用するので、これに言及することは重要です.
    次のように、コンテナレジストリから最新のイメージで展開が作成され、更新されます
    # Creating a deployment
    helm install -f values.yml --set image.version=<latest> example-service example-service
    
    # Updating a deployment
    helm upgrade -f values.yml --set image.version=<latest> example-service example-service
    
    
    GKE hardening guideはKubernetesクラスタへのネットワークアクセスを制限し、private clusterとして作成することを示唆している.これは公共のインターネットからノードを隔離します、そして、Kubernetes APIサーバへのアクセスは特定の信頼されたネットワークIPだけにさらに制限されることができます.
    我々が始めたとき、我々はクラスタを管理して、アップグレードを手動で展開するのに用いられる信頼できるマシンのIPで、helmをつくりました.また、(非常にクールな)UIを展開するために使用することができるUIツールを構築し、展開&スケール展開.
    この時点で、これはすべて一緒に見た方法です

    長い間、我々は継続的な展開の必要性を感じ始めるまで、これは本当にうまくいきました.私はそれをhereの議論を共有します.

    挑戦


    パイプラインへの連続配備を追加する最も簡単な方法は、最新のイメージをクラスタに展開するGithubアクションパイプラインに別のステップを追加することでした.アクションを更新しましょう.
        # ...
        # same as before
        # ...
    
          - uses: GoogleCloudPlatform/github-actions/setup-gcloud@master # Setup gcloud
            with:
              service_account_key: ${{ secrets.GCP_SA_KEY }} # ServiceAccount key with necessary rights added as a secret on Github.
    
            # Configure credentials for docker
          - run: gcloud auth configure-docker
    
            # Build the Docker image
          - run: docker build -t gcr.io/example.com/${{ github.event.repository.name }}:${{ github.sha }} .
    
            # Push the Docker image to Google Container Registry
          - run: docker push gcr.io/example.com/${{ github.event.repository.name }}:${{ github.sha }}
    
            # Generate kubeconfig entry
          - run: gcloud container clusters get-credentials <cluster-name> --zone <zone> --project <project>
    
            # Install helm
          - uses: azure/setup-helm@v1
            id: install
    
            # Deploy latest version
          - run: helm upgrade -f values.yaml --set image.version=${{ github.sha }} example-service example-service
    
    
    残念ながら、これは動きません.パイプラインは最後のステップで失敗します.これは、Kubernetesサーバーは、パブリックインターネット上で到達できないためです.

    可能な解決策(と彼らが来る問題のバッグ)

  • クラスタを公共のセットアップ作業の簡単な方法にし、クラスタをインターネット上に到達させる.しかし、これはクラスタを露出させる費用であり、セットアップをより安全にしませんでした.トレードオフは価値がないだろう.
  • アイディアの中にアクションランナーIPSを追加しましたが、最初はよく考えていましたが、少し深く掘り下げてみると、ジョブを実行するサーバは5 Azure regions in the USから何かを見つけることができました.GitHubページは定期的に更新されるIP範囲を含むJSONファイルをダウンロードする方法を示します.このパスを進めるのは、常にリストを取得し、許可リストを更新することを意味します.
    自動化された解決策は最善でしたが、私はファイルを解析したくありませんでした.幸いにも、Azure雲はService TagsのためにIP範囲を得ることができます.問題はすべての5つの領域のために結合されたすべてのIP範囲が1100 +(私がチェックした最後の時)であり、GKEは50 entries for authorized networksしか持っていないということです.
    〈挿入イメージ〉壁に頭をぶつける
  • は、Aquure IP範囲からのアクセスを許可するライトプロキシサーバを実行します.IPSのリストで更新し続けるために、プログラム的に設定することができた、簡単で、外箱の解決策がありませんでした.
  • 私は、展開を引き起こすために呼び出すことができる公的にアクセス可能なAPIを作成しなければならないかどうか考えました.たぶん、私はkubeconfigと認証し、それを安全に呼び出すことができます.(It's not!)それは、ちょうどこの道を進む権利を感じませんでした.
  • これらのすべては様々な理由のために不自然な解決のようでした.ファイアウォールをプログラム的に設定することができなかったので、私は壁にぶつかったようでした.

    解決策


    私は他の仕事に取り組んでいる間、私の頭の後ろで解決のために考え続けました.私はCDサーバーを管理したくありませんでした、私はクラスタを露出させることを危険にさらしたくありませんでした、そして、私はKubernetesコントロールサーバーに達するためにallow-listを望みました.
    私は、それが最終的に私を襲うまで、私が認めたいより多くの時間を解決を探している行動のYAMLをじっと見つめました-私は、信頼できるIPから配備ステップを実行するだけである必要がありました.
    私は仕事を2 - Basic Auth & helmに分割しました.
  • は、コードをコンパイルし、テストを実行し、アーティファクトを作成し、Dockerイメージをビルドし、コンテナーレジストリにプッシュする、CPU&メモリ集約部分です.
  • の部分はbuildで最新のイメージをちょうど展開します.
    Gythub主催のアクションランナーでdeployが実行されると、buildself-hosted action-runnerで実行されます.
  • この自己ホストランナーは、Googleのクラウドの中に静的なIPを持つ計算機です.この静的IPをKubernetes権限のIPリストの許可リストに設定できました.
    更新された設定は次のようになります.

    以下は更新されたdeployです.
    on:
      push:
        branches:
          - master
    
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v2 # checkout repo
          - uses: actions/setup-java@v1 # Set up latest Java 14
            with:
              java-version: 14
    
          - name: Build with Gradle
            run: ./gradlew clean build
    
          - uses: GoogleCloudPlatform/github-actions/setup-gcloud@master # Setup gcloud
            with:
              service_account_key: ${{ secrets.GCP_SA_KEY }} # ServiceAccount key with necessary rights added as a secret on Github.
    
            # Configure credentials for docker
          - run: gcloud auth configure-docker
    
            # Build the Docker image
          - run: docker build -t gcr.io/example.com/${{ github.event.repository.name }}:${{ github.sha }} .
    
            # Push the Docker image to Google Container Registry
          - run: docker push gcr.io/example.com/${{ github.event.repository.name }}:${{ github.sha }}
    
      deploy:
        runs-on: self-hosted
        needs: [build] # to block for the build step to complete successfully
        steps:
          - uses: actions/checkout@v2
    
          - uses: GoogleCloudPlatform/github-actions/setup-gcloud@master # Setup gcloud
            with:
              service_account_key: ${{ secrets.GCP_SA_KEY }}
    
            # Generate kubeconfig entry
          - run: gcloud container clusters get-credentials <cluster-name> --zone <zone> --project <project>
    
            # Install helm
          - uses: azure/setup-helm@v1
            id: install
    
            # Deploy latest version
          - run: helm upgrade -f values.yaml --set image.version=${{ github.sha }} example-service example-service
    
    
    私はそれを試して🎉.
    それ以来、我々はすべてのサービスを分割helmbuildジョブのようなパターンを使用して更新されている幸せに各変更を持つすべての環境にコードを出荷している.

    あなたがこれまで読んだならば、私はあなたから学ぶことを知りたいですか?
  • あなたはどう思いますか?
  • githubのアクションも使えますか?
  • Kubernetesにも継続的に展開しますか?
  • どうやってそれをするの?そして、できればどうやって変えるの?
  • 免責事項


    ここで示した設定は、上記のトピックにフォーカスするために実際の環境に存在する他のキーコンポーネントを除外する簡略化版です.