CircleCI から、新しい Arm ベースのコンピューティングがプレビュー版としてリリースされました。このプレビュー版へのアクセスは、こちらから申請できます。

Arm プロセッサとアーキテクチャは、 開発チームの多数のアプリケーション インフラストラクチャにコンピューティング ノードとして採用され、普及が進んでいます。これからも、マイクロサービス、アプリケーション サーバー、データベースなどのワークロードをコスト効率よく実行するために、Arm アーキテクチャの需要は高まっていくでしょう。CircleCI ではこれまで、Arm ベースのコンピューティングを求める声に応じてセルフホスト ランナーを提供していました。しかし、Arm ベースのコンピューティングでアプリケーションをビルド、テスト、デプロイしたいというお客様の数はますます増えています。そこで、全 CircleCI ユーザー向けに 新しい Arm ベースのリソース クラス をリリースいたしました。このクラスを使用することで、自身でインフラストラクチャを管理することなく、CI/CD パイプラインの Arm ベースのインスタンス上でコードを実行することができます。本チュートリアルでは、この新しいArm リソース クラス を紹介してから、これらのクラスをパイプライン内で使用して Arm 向けアプリケーションのビルド、テスト、デプロイを行う方法について説明します。

前提条件

本チュートリアルを進めるには、以下の作業が必要です。

Arm コンピューティング リソース クラス

Arm コンピューティング リソース クラスは現在プレビュー版であり、Machine Executor として提供されています。そのため、パイプラインの構成定義では Machine Executor として実装します。Arm リソース クラスを使用してジョブを実行するには、プレビューへのアクセスが必要であることに注意してください。このチュートリアルの以下のセクションでは、Arm ベースの Executor で CI/CD パイプラインを構成および実行する方法を説明します。また、Terraformとインフラストラクチャのコード化を使用し、AWS Graviton2 コンピューティング ノードを基盤としたAWS ECS クラスタ を作成、デプロイ、破棄する方法についても説明します。

config.yml に Arm コンピューティングを実装する

下記のパイプライン構成例に、Arm リソース クラスの定義方法を示します。

version: 2.1
orbs:
  node: circleci/node@4.2.0
jobs:
  run-tests:
    machine:
      image: ubuntu-2004:202101-01
    resource_class: arm.medium
    steps:
      - checkout
      - node/install-packages:
          override-ci-command: npm install
          cache-path: ~/project/node_modules
      - run:
          name: 単体テストの実行
          command: |
            ./node_modules/mocha/bin/mocha test/ --reporter mochawesome --reporter-options reportDir=test-results,reportFilename=test-results
      - store_test_results:
          path: test-results
      - store_artifacts:
          path: test-results          
  build_docker_image:
    machine:
      image: ubuntu-2004:202101-01
    resource_class: arm.medium
    steps:
      - checkout
      - run:
          name: "Docker イメージ ARM V8 のビルド"
          command: |
            export TAG='0.1.<< pipeline.number >>'
            export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME
            docker build -t $DOCKER_LOGIN/$IMAGE_NAME -t $DOCKER_LOGIN/$IMAGE_NAME:$TAG .
            echo $DOCKER_PWD | docker login -u $DOCKER_LOGIN --password-stdin
            docker push -a $DOCKER_LOGIN/$IMAGE_NAME
workflows:
  build:
    jobs:
      - run-tests
      - build_docker_image

このサンプルコードに含まれる run-tests: ジョブは、Machine Executor を指定して Arm コンピューティング ノード リソース クラスを割り当てる方法を示しています。image: キーでは、Executor に割り当てられるオペレーティング システムを指定します。resource_class:では、利用する CircleCI のリソース クラス を指定します。 ここでは arm.medium リソース クラス タイプを使用しています。このクラスでは、Arm アーキテクチャとリソース上でこれらのコードを実行およびビルドできます。build_docker_image:ジョブでは、Arm コンピューティング インフラストラクチャ(AWS Graviton2 など)に確実にデプロイ可能な Arm64 対応の Docker イメージを、arm.medium リソース クラスでビルドしています。

  version: 2.1
  orbs:
    node: circleci/node@4.2.0
  commands:
    install_terraform:
      description: "使用する Terraform のバージョンとアーキテクチャを指定 [amd64 または arm64]"
      parameters:
        version:
          type: string
          default: "0.13.5"
        arch:
          type: string
          default: "arm64"
      steps:
        - run:
            name: Terraform クライアントのインストール
            command: |
              cd /tmp
              wget https://releases.hashicorp.com/terraform/<<
                parameters.version >>/terraform_<<
                parameters.version >>_linux_<< 
                parameters.arch >>.zip
              unzip terraform_<< parameters.version >>_linux_<<
                parameters.arch >>.zip
              sudo mv terraform /usr/local/bin
  jobs:
    run-tests:
      machine:
        image: ubuntu-2004:202101-01
      resource_class: arm.medium
      steps:
        - checkout
        - node/install-packages:
            override-ci-command: npm install
            cache-path: ~/project/node_modules
        - run:
            name: 単体テストの実行
            command: |
              ./node_modules/mocha/bin/mocha test/ --reporter mochawesome --reporter-options reportDir=test-results,reportFilename=test-results
        - store_test_results:
            path: test-results
        - store_artifacts:
            path: test-results          
    build_docker_image:
      machine:
        image: ubuntu-2004:202101-01
      resource_class: arm.medium
      steps:
        - checkout
        - run:
            name: "Docker イメージ ARM V8 のビルド"
            command: |
              export TAG='0.1.<< pipeline.number >>'
              export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME
              docker build -t $DOCKER_LOGIN/$IMAGE_NAME -t $DOCKER_LOGIN/$IMAGE_NAME:$TAG .
              echo $DOCKER_PWD | docker login -u $DOCKER_LOGIN --password-stdin
              docker push -a $DOCKER_LOGIN/$IMAGE_NAME
    deploy_aws_ecs:
      machine:
        image: ubuntu-2004:202101-01
      resource_class: arm.medium
      steps:
        - checkout
        - run:
            name: ローカルでの .terraformrc ファイルの作成
            command: echo "credentials \"app.terraform.io\" {token = \"$TERRAFORM_TOKEN\"}" > $HOME/.terraformrc
        - install_terraform:
            version: 0.14.2
            arch: arm64    
        - run:
            name: AWS ECS クラスタへのアプリケーションのデプロイ
            command: |
              export TAG=0.1.<< pipeline.number >>
              export DOCKER_IMAGE_NAME="${DOCKER_LOGIN}/${CIRCLE_PROJECT_REPONAME}"
              cd terraform/aws/ecs
              terraform init
              terraform apply \
                -var docker_img_name=$DOCKER_IMAGE_NAME \
                -var docker_img_tag=$TAG \
                --auto-approve
    destroy_aws_ecs:
      machine:
        image: ubuntu-2004:202101-01
      resource_class: arm.medium
      steps:
        - checkout
        - run:
            name: ローカルでの .terraformrc ファイルの作成
            command: echo "credentials \"app.terraform.io\" {token = \"$TERRAFORM_TOKEN\"}" > $HOME/.terraformrc
        - install_terraform:
            version: 0.14.2
            arch: arm64    
        - run:
            name: AWS ECS クラスタの破棄
            command: |
              cd terraform/aws/ecs
              terraform init
              terraform destroy --auto-approve              
  workflows:
    build:
      jobs:
        - run-tests
        - build_docker_image
        - deploy_aws_ecs
        - approve_destroy:
            type: approval
            requires:
              - deploy_aws_ecs
        - destroy_aws_ecs:
            requires:
              - approve_destroy

AWS ECS にデプロイする

前のセクションのサンプル コードでは、Arm リソース クラスをパイプライン内で使用する方法について説明しました。本セクションでは、このコードを拡張してECS クラスタなどの AWS リソースを作成する方法について説明します。リソースの作成にあたっては、AWS Graviton2 EC2 コンピューティング ノードを基盤とし、Terraform とインフラストラクチャのコード化を使用します。

  version: 2.1
  orbs:
    node: circleci/node@4.2.0
  commands:
    install_terraform:
      description: "使用する Terraform のバージョンとアーキテクチャを指定 [amd64 または arm64]"
      parameters:
        version:
          type: string
          default: "0.13.5"
        arch:
          type: string
          default: "arm64"
      steps:
        - run:
            name: Terraform クライアントのインストール
            command: |
              cd /tmp
              wget https://releases.hashicorp.com/terraform/<<
                parameters.version >>/terraform_<<
                parameters.version >>_linux_<< 
                parameters.arch >>.zip
              unzip terraform_<< parameters.version >>_linux_<<
                parameters.arch >>.zip
              sudo mv terraform /usr/local/bin
  jobs:
    run-tests:
      machine:
        image: ubuntu-2004:202101-01
      resource_class: arm.medium
      steps:
        - checkout
        - node/install-packages:
            override-ci-command: npm install
            cache-path: ~/project/node_modules
        - run:
            name: 単体テストの実行
            command: |
              ./node_modules/mocha/bin/mocha test/ --reporter mochawesome --reporter-options reportDir=test-results,reportFilename=test-results
        - store_test_results:
            path: test-results
        - store_artifacts:
            path: test-results          
    build_docker_image:
      machine:
        image: ubuntu-2004:202101-01
      resource_class: arm.medium
      steps:
        - checkout
        - run:
            name: "Docker イメージ ARM V8 のビルド"
            command: |
              export TAG='0.1.<< pipeline.number >>'
              export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME
              docker build -t $DOCKER_LOGIN/$IMAGE_NAME -t $DOCKER_LOGIN/$IMAGE_NAME:$TAG .
              echo $DOCKER_PWD | docker login -u $DOCKER_LOGIN --password-stdin
              docker push -a $DOCKER_LOGIN/$IMAGE_NAME
    deploy_aws_ecs:
      machine:
        image: ubuntu-2004:202101-01
      resource_class: arm.medium
      steps:
        - checkout
        - run:
            name: ローカルでの .terraformrc ファイルの作成
            command: echo "credentials \"app.terraform.io\" {token = \"$TERRAFORM_TOKEN\"}" > $HOME/.terraformrc
        - install_terraform:
            version: 0.14.2
            arch: arm64    
        - run:
            name: AWS ECS クラスタへのアプリケーションのデプロイ
            command: |
              export TAG=0.1.<< pipeline.number >>
              export DOCKER_IMAGE_NAME="${DOCKER_LOGIN}/${CIRCLE_PROJECT_REPONAME}"
              cd terraform/aws/ecs
              terraform init
              terraform apply \
                -var docker_img_name=$DOCKER_IMAGE_NAME \
                -var docker_img_tag=$TAG \
                --auto-approve
    destroy_aws_ecs:
      machine:
        image: ubuntu-2004:202101-01
      resource_class: arm.medium
      steps:
        - checkout
        - run:
            name: ローカルでの .terraformrc ファイルの作成
            command: echo "credentials \"app.terraform.io\" {token = \"$TERRAFORM_TOKEN\"}" > $HOME/.terraformrc
        - install_terraform:
            version: 0.14.2
            arch: arm64    
        - run:
            name: AWS ECS クラスタの破棄
            command: |
              cd terraform/aws/ecs
              terraform init
              terraform destroy --auto-approve              
  workflows:
    build:
      jobs:
        - run-tests
        - build_docker_image
        - deploy_aws_ecs
        - approve_destroy:
            type: approval
            requires:
              - deploy_aws_ecs
        - destroy_aws_ecs:
            requires:
              - approve_destroy

このコードは、前のセクションのパイプライン構成例を拡張したものです。注目点は、数個の新しいジョブ(deploy_aws_ecs:, approve_destroy:, destroy_aws_ecs: ジョブ)が定義されていることです。これらを詳しく見ていく前に、まず commands: および install_terraform: の各要素について説明します。

install_terraform: コマンド

CircleCI では、パイプライン パラメーターを使用して構成コードのカプセル化と再利用を行えます。install_terraform: コマンドは、再利用可能なパイプライン コードを定義する一例です。パイプラインで特定のコマンドを繰り返し実行する場合は、パイプライン構成の拡張性と一元管理のために、再利用可能なcommand:要素を定義することをお勧めします。deploy_aws_ecs: ジョブと destroy_aws_ecs:ジョブはどちらも Terraform コードを実行するので、パイプラインではTerraform cliのダウンロードとインストールを複数回行う必要があります。そこで、install_terraform:コマンドにより再利用性を高めています。

  commands:
    install_terraform:
      description: "使用する Terraform のバージョンとアーキテクチャを指定 [amd64 または arm64]"
      parameters:
        version:
          type: string
          default: "0.13.5"
        arch:
          type: string
          default: "arm64"
      steps:
        - run:
            name: Terraform クライアントのインストール
            command: |
              cd /tmp
              wget https://releases.hashicorp.com/terraform/<<
                parameters.version >>/terraform_<<
                parameters.version >>_linux_<< 
                parameters.arch >>.zip
              unzip terraform_<< parameters.version >>_linux_<<
                parameters.arch >>.zip
              sudo mv terraform /usr/local/bin

このコード ブロックでは、再利用可能なコマンドinstall_terraform:を定義しています。parameters:キーはパラメーターのリストを保持します。version: パラメーターと arch:パラメーターで、Terraform CLI のバージョンと CPU アーキテクチャをそれぞれ定義しています。これらのパラメーターを使用して、Executor でのクライアントのダウンロードとインストールを行います。このコード ブロックはcommand: 要素であるため、コマンドのsteps:キーを定義する必要があります。上記の例では、run: 要素で対応する command: キーを実行しています。 このキーは、<< parameter.version >> および << parameter.arch >> 変数を使用してクライアントのバージョン番号と CPU アーキテクチャを指定し、特定の Terraform クライアントをダウンロードします。パイプライン パラメーター は、パイプライン構成における機能の最適化と一元管理に非常に便利です。詳しく知りたい方は、こちらのページをご覧ください。

deploy_aws_ecs ジョブ

パイプラインで定義されているdeploy_aws_ecs: ジョブは、インフラストラクチャのコード化を活用して Amazon ECS クラスタを新規作成します。これには、仮想プライベート ネットワーク (VPC)、サブネット、ルート テーブル、アプリケーション ロード バランサー、EC2 自動スケーリング グループといった必要なリソースがすべて含まれます。このジョブは、アプリケーションのデプロイと実行に必要なすべてのインフラストラクチャを作成およびプロビジョニングします。対象のアーキテクチャは Arm なので、AWS ECS クラスタは AWS Gravtion2 ECS コンピューティング ノードで構成する必要があります。これらの AWS Gravtion2 ECS コンピューティング ノードで、前のパイプライン ジョブにおける Arm ベースの Docker アプリケーション イメージ ビルドを実行します。

  deploy_aws_ecs:
    machine:
      image: ubuntu-2004:202101-01
    resource_class: arm.medium
    steps:
      - checkout
      - run:
          name: ローカルでの .terraformrc ファイルの作成
          command: echo "credentials \"app.terraform.io\" {token = \"$TERRAFORM_TOKEN\"}" > $HOME/.terraformrc
      - install_terraform:
          version: 0.14.2
          arch: arm64    
      - run:
          name: AWS ECS クラスタへのアプリケーションのデプロイ
          command: |
            export TAG=0.1.<< pipeline.number >>
            export DOCKER_IMAGE_NAME="${DOCKER_LOGIN}/${CIRCLE_PROJECT_REPONAME}"
            cd terraform/aws/ecs
            terraform init
            terraform apply \
              -var docker_img_name=$DOCKER_IMAGE_NAME \
              -var docker_img_tag=$TAG \
              --auto-approve

このコード ブロックでは、先ほど触れた install_terraform:コマンドの使い方を示しています。version: パラメーターを 0.14.2、arch: パラメーターを arm64 に設定しました。最後の run:要素は Terraform を初期化します。そして、このパイプライン実行で作成された Docker イメージ名とタグの値を渡す対応パラメーターを指定して、terraform applyコマンドを実行します。これらが完了すると、アプリケーションが作成され、完全な機能を備えた AWS ECS Graviton2 ベースのクラスタにデプロイされます。

destroy_aws_ecs ジョブ

ここまでは、deploy_aws_ecsで AWS ECS のインフラストラクチャを作成してきました。その名の通り destroy_aws_ecs ジョブはこの逆で、作成したすべてのインフラストラクチャとリソースをプログラムで破棄します。このジョブを使用すれば、極めてクリーンな方法で不要なインフラストラクチャを終了させることができます。

  destroy_aws_ecs:
    machine:
      image: ubuntu-2004:202101-01
    resource_class: arm.medium
    steps:
      - checkout
      - run:
          name: ローカルでの .terraformrc ファイルの作成
          command: echo "credentials \"app.terraform.io\" {token = \"$TERRAFORM_TOKEN\"}" > $HOME/.terraformrc
      - install_terraform:
          version: 0.14.2
          arch: arm64    
      - run:
          name: AWS ECS クラスタの破棄
          command: |
            cd terraform/aws/ecs
            terraform init
            terraform destroy --auto-approve

ジョブ定義のほとんどは直前のコード ブロックと同じですが、最後の run: 要素に注目してください。この要素では、Terraform の初期化コマンドと、前のステップで作成したすべてのリソースを破棄する terraform destroy コマンドを発行しています。

ワークフロー: approve_destroy ジョブ

最後に扱うのは、構成例のworkflows: 要素にある approve_destroy:です。このジョブは 手動承認タイプです。 手動での承認が行われるまでワークフローを意図的に停止して保留状態にします。ここでは、CircleCI ダッシュボードでボタンを押下しなければ destroy_aws_ecs: を実行できないようにしています。この承認ジョブがない場合は、パイプラインでは自動的に破棄ジョブをトリガーし、前のジョブで作成したリソースをすべて終了させます。承認タイプのジョブは、パイプライン実行において手動での操作や承認が必要な場合に便利です。

まとめ

CircleCI に、Arm コンピューティング ノードとして Arm 対応の Executor が加わりました。これにより、開発パイプラインで Arm アーキテクチャを利用できます。このチュートリアルでは、CircleCI の Arm コンピューティング ノードをパイプラインの Executor として実装する方法を紹介しました。また、Terraform とインフラストラクチャのコード化を使用して、AWS Graviton2 EC2 ノードを基盤とする AWS ECS クラスタにアプリケーションをデプロイする方法も示しました。このチュートリアルで扱ったサンプル コードはすべて GitHub にありますので、ぜひご覧ください。ご意見、ご感想は Twitter で @punkdata宛てにお寄せください。

最後までお読みいただき、ありがとうございました。