SageMaker Code Editorの紹介

はじめに

こんにちは。弥生R&D室のsiidaです。R&D室ではSageMakerを使用して機械学習 (ML) のプロジェクトを進めています。SageMakerはMLのための様々な機能が搭載されたサービスであり、データ分析からモデル訓練、ひいてはワークフローの構築まで、SageMakerの中で完結させることができます。

SageMakerは元々JupyterLabのIDEを備えていましたが、こちらはNotebookの実行に最適化されたIDEであるため、データ分析であればともかくモデリングやMLシステムの構築には不向きな点がありました。

そこでCode Editorの出番です。こちらはVSCodeを元に作られたIDEで、事実上ブラウザで動作するVSCodeとして扱うことができます。ターミナルもVSCode同様の扱いとなっているため、あえてターミナルを全画面に表示することでiTermのようなローカルのターミナルと同じように操作することもできます。Vim派のユーザーにもおすすめなツールです。

本日はこのCode Editorの使い方を紹介します。

続きを読む

作っているだけでは分からない、「お客さま」のこと

こんにちは、弥生の開発本部でPMをしているシダです。 「弥生会計オンライン」の開発に携わっています。

システム開発においては、サービスプラットフォームやソフトウェア、フレームワークなど数多くの必要な要素があります。
本ブログでもそういった情報を多く取り扱っております。

ですが、仕事としてものづくりをするにあたっては「誰のために、どういった価値を届けるか」という点も重要だと私は考えています。
中でも「実際のお客さまの声」というのは「世に出したものがどう受け入れられたか」を知るうえで非常に大事な情報となります。

そういった背景もあり、私のチームでは今年から顧客サービス本部*1(以下、CS本部)との交流の取り組みを行っています。
以前から他のチームでも実践していたことなのですが、今年から私のチームでも開始しました。

過去に本ブログでも「弥生会計」開発チームの同様の取り組みを紹介しています。

tech-blog.yayoi-kk.co.jp

重複する内容もあるかもしれませんが、PMの目線、オンラインサービスの目線など、異なる目線でお伝えできることがあると考えたため、その取り組みについてご紹介したいと思います。

そもそものきっかけ

開発本部では2023年10月より「本部をまたいだコミュニケーション、意思決定の速度を向上させる​」という目標を掲げていました。 その実現のために、他本部が通常業務で行っている内容を把握できるよう、以下のような施策を実施しています。

・開発本部内で実施しているLT大会に、他本部の方に特別講演という形で参加してもらう
・営業現場を知るため、パートナービジネス本部の会計事務所訪問に同行する
・他本部と意見交換や質疑応答を行う場を設ける

今回の「お客さまの声を聴く」施策も、この一環で企画されたものです。

「交流会」の実施

まずはCS本部のメンバーとのオンライン交流会の場を設けました。

弥生は日本各地に拠点がありますが、開発本部の拠点は東京、CS本部の拠点は大阪・札幌ということで、メンバー同士が直接を顔合わせる機会は殆どありません。
そのためZoomを用いてのオンライン交流会を行いました。

私はPMという立場上、CS本部の方とは定期的にコミュニケーションをとる機会があります。
ただ、それはあくまで各本部のリーダークラス同士の交流であり、現場に近い方とのコミュニケーションの機会は殆どありませんでした。

また、両本部の現場に近いメンバーは、そもそも部横断でのコミュニケーションの機会自体がありません。
そのため、普段は耳にできない現場レベルでの声を共有しあえる機会、という点において価値のある取り組みだと考えました。

私自身も、実際にお客さま対応をされている方と話すのは初めてであり、現場目線での話が聴けたのは非常にためになりました。

実際に上がった話の一例

良かった声

・サービスの初期化処理の動線を変更したことで、誤操作やお問い合わせを削減できた
・画面項目に説明(ツールチップ等)を増やすことでお問い合わせを抑制でき、お問い合わせへの回答も容易になった
・決算時における按分処理などの複雑な処理を自動で処理するようにしたことで、お問い合わせを抑制できた

課題を感じた声

・法令対応を行ったが、そもそも制度自体が非常に難解なため、お客さまへの説明が大変
・法令対応に伴い設定画面に項目を追加したが、それらをお客さまに理解してもらったうえで、正しいものを選択してもらうよう誘導するのが大変
・確定申告に必要な情報を入力する際には、必要な人に、必要な情報のみを見せるようにしたい
・確定申告が簡単すぎて、却って不安に感じているようなお問い合わせがある

良かった声については「対応して良かったな」と心から思いました。自分たちの作ったものが実際にお客さまや現場のメンバーの方々に受け入れられており、非常に嬉しく思いました。

一方で課題を感じた声については、今後どう解消していくか考えていく必要があります。お客さまの事だけでなく、お問い合わせ対応をするCS本部の方の事も考えたうえでの製品開発が必要だなと改めて感じました。

また、過去にCS本部から上がった要求について「本当にこの改善は効果があるのか…?」と内心思っていたものもあったのですが、それらがお客さまにどのような印象を与えているか、CS本部におけるお客さま対応にどう役立っているか、という点を聴けたのは非常に良かったです。
今まで以上に自信を持って開発に取り組めると感じました。

※余談ですが、会自体は非常にアットホームな雰囲気で進めることができました。製品品質やリリース頻度に対する不満などを受けることはなく、内心ホッとしました。

「顧客の声を聴く会」の実施

続いて、CS本部が実際にお客さま対応をした際の音声ログの視聴会を実施しました。
開発本部のメンバーは普段はお客さまの声を直接聴くことはありません。そのため実際のお客さまの声を聴くことで今後の製品開発に活かせないか、というのが目的です。

ここでは上がった声のうち2種類を紹介したいと思います。

・製品では対応していない機能への要望

お客さまの操作において「〇〇といった操作はできないか?」という声がありました。
現状対応予定がないもの、いずれ対応する予定は立っているもの、そもそも開発側で認知していなかったものなど、様々でした。

あくまで一部の声かもしれませんが、対応されていないことによる落胆される方や、逆に熱い要望を送って下さる方もおり、非常に考えさせられました。
とはいえ、あくまで一部の声であるため、すべてを安易に受け止めるのではなく『より多くのお客さまを幸せにするにはどうすればいいか?』はしっかりと考える必要があります。
こういった点はCS本部とも協力し、少しでも解消していくことが必要だと改めて感じました。

・製品仕様に対する質問

弥生のオンライン製品は「初心者にも使いやすく」をモットーにしています。そのため「操作説明やFAQを充実させる」「必要な箇所のみを入力させる」「迷いにくい画面構成とする」など、多くの工夫をしております。
ただ、それでも操作や仕様に関する質問はゼロにはなりません。

特に、昨年対応したインボイス制度*2については、製品内での説明を手厚くしたものの、やはりお客さまからは多くのお問い合わせが発生していることがわかりました。

インボイス制度への対応では、画面項目も新たに追加しております。
この対応は2年以上にも渡ったため、私を含めた開発チームはいつの間にか追加した画面項目に対してあまり違和感を感じなくなっていました。
が、音声ログを聞いたことで、それらがお客さまに驚きを持って迎えられたことを実感しました。

私も、慣れ親しんだwebページやアプリなどが急に変わったら大きく戸惑いますし、単純に使い慣れていないというだけで「分かりにくい、使いづらい」という印象を抱いてしまいます。

特に会計ソフトは個人事業主や法人のお客さまにとって『必ずしも、積極的に使いたいものではない』と考えています。可能なら本業によりリソースを割きたい、という思いもあるはずだと私は考えます。 そういった背景も踏まえると、機能追加によりお客さまが感じたストレスは相当のものであったはずです。 お客さまの目の前で起こっていたことを知るという意味で、大きな収穫のあった取り組みだと感じています。

所感

今回は2つの取り組みを紹介しました。
私自身はCS本部の代表の方とのコミュニケーションは頻繁にとっていましたが、実際の現場の声を聴くとまた違った刺激がありました。

また、普段CS本部とあまり接点がないメンバーにとっては、私以上に得られたものが多かったと考えます。
この取り組みを経て新たな刺激を受け、それを製品開発に還元してもらえれば、PMとしても非常に嬉しく思います。

まとめ

私の現在の役割は文字通り「プロジェクトマネージャー」の側面が強く、「お客さまのためにどういった製品を作るべきか」よりも「開発チームの成功」により重きをおいているのが正直なところです。
もちろん、それだけでは真に価値のある製品は作れないことは自覚しております。

ですがCS本部の存在により、お客さまが困っていること、お客さまが求めているものを間接的に知ることができます。
弥生のカスタマーセンターは業界でも随一の規模であり、また弥生シリーズの有償契約者数も100万件を超えています。 そういった多数のお客さまの声を聴き、製品開発に活かせることは開発側にとっても非常に大きいメリットです。だからこそ私も「開発チームの成功」に全力を注ぐことができています。

今後もこの強みを最大限に活かし、より多くのお客さまに満足してもらえる製品を開発していきます。


弥生では一緒に働く仲間を募集しています。 herp.careers

*1:弥生の製品・サービスをご利用中のお客さまからのお問い合わせや改善要望を承るチーム

*2:2023年10月1日から導入された、新しい仕入税額控除の方式

AWS認定資格取得の意義と生成AIの活用

こんにちは、インフラチームの今泉です。
私事ですがここ1年でAWS認定資格のSAP、SCSの再認定、新たにDVA、DOPの認定と、計4つの認定を受験しました。
このままコンプリートを目指していた矢先、AWS認定資格の見直しにより資格の種類が変更されました。
(持っていたDatabase Specialty が廃止されちょっと悲しくなっています、、、)
一方で、数年前から生成AIが業務で利用されるようになってきており、弥生でも利活用が進んでいます!

生成AIが台頭してきた時代においてAWS認定資格を取得する必要があるのか、このタイミングで今一度考えてみました。

AWS認定資格とは

AWS認定資格とは、Amazonが運営するクラウドコンピューティングサービスである「Amazon Web Services(AWS)」の各種サービスを効果的に活用するために必要な知識とスキルを証明する資格試験です。

AWS 認定 – AWS クラウドコンピューティング認定プログラム

AWS認定資格

AWS認定資格の変更点

AWS認定資格は時代に合わせて変更されています。
直近でAI・データ活用・機会学習の需要の高まりに対応するためにFoundational、Associateの資格が追加されています。また一部のSpecialityについては廃止されました。
Specialtyの資格が半分となりましたが、廃止された各分野についてはSkill builderのデジタルトレーニングリソースで提供されています。

資格名 種類 新規/続投/廃止
AWS Certified Cloud Practitioner (CLF) Foundational 続投
AWS Certified AI Practitioner ※ Foundational 新規
AWS Certified Solutions Architect - Associate (SAA) Associate 続投
AWS Certified Developer - Associate (DVA) Associate 続投
AWS Certified SysOps Administrator - Associate (SOA) Associate 続投
AWS Certified Data Engineer - Associate (ADE) Associate 新規
AWS Certified Machine Learning Engineer - Associate ※ Associate 新規
AWS Certified Solutions Architect - Professional (SAP) Professional 続投
AWS Certified DevOps Engineer - Professional (DOP) Professional 続投
AWS Certified Security - Specialty (SCS) Specialty 続投
AWS Certified Advanced Networking - Specialty (ANS) Specialty 続投
AWS Certified Machine Learning - Specialty (MLS) Specialty 続投
AWS Certified Database - Specialty Specialty 廃止
AWS Certified: SAP on AWS - Specialty Specialty 廃止
AWS Certified Data Analytics - Specialty Specialty 廃止

※ AI PractitionerとMachine Learning Engineer - Associateについては執筆時点ではbeta版となります。

生成AIの活用について

すでにビジネスプロセスや日常生活など、様々な環境で生成AIが活用されていると思います。
AWS利用でもCloudFormationやLambdaでのCDKのコード作成などいたるところで利用できます。
私自身も最近はOpenSearchのディスク容量をCloudWatchのアラームをトリガーに自動で追加するためLambda関数の例をMicrosoft Copilotを利用して作成しました。

# Microsoft Copilotへの質問
OpenSearchのディスク容量をCloudWatch Alarmをトリガーに自動で追加するLambdaを作成してみてください。

Microsoft Copilotの回答ではLambda関数以外にもIAMロールの作成も提案してくれました。

# Microsoft Copilotからの回答
1. 必要なIAMロールの作成
まず、Lambda関数が必要な権限を持つIAMロールを作成します。

~~~IAMロール、ポリシーは省略~~~

2. Lambda関数の作成
次に、Lambda関数を作成します。以下はPythonでの例です。

---
import boto3
import json

def lambda_handler(event, context):
    es_client = boto3.client('es')
    cloudwatch_client = boto3.client('cloudwatch')
    
    # CloudWatchアラームの状態を確認
    alarm_name = 'YourCloudWatchAlarmName'
    response = cloudwatch_client.describe_alarms(
        AlarmNames=[alarm_name]
    )
    
    alarm_state = response['MetricAlarms'][0]['StateValue']
    
    if alarm_state == 'ALARM':
        # OpenSearchのディスク容量を追加
        domain_name = 'YourOpenSearchDomainName'
        response = es_client.update_elasticsearch_domain_config(
            DomainName=domain_name,
            EBSOptions={
                'EBSEnabled': True,
                'VolumeSize': 100  # 追加するディスク容量(GB)
            }
        )
        return {
            'statusCode': 200,
            'body': json.dumps('Disk space increased successfully')
        }
    else:
        return {
            'statusCode': 200,
            'body': json.dumps('No action needed')
        }
---

実際に動作するかどうかは確認が必要ですが、一から作成するよりもかなりの時間を短縮することができました。
Lambda関数だけでなく、IAMロール、それに必要なポリシーの提案までしてくれるとは思いませんでした!
実際のアカウント番号やarnの流出などセキュリティへの配慮は十分に行う必要はありますが、生産性・品質向上には利用できるようになっているかと思います。

なぜAWS認定資格を受けるのか

ここまで生成AIが多くのことを自動化してくれるので、AWS認定資格はもう必要ないのではと考える方もいるかもしれません。
私自身も生成AIが登場した当初、「これ資格の意味がなくなるのでは?」と思ったことがあります。
しかし、実際に生成AIを業務で活用してみた結果、AWS認定資格を取得するメリットは以下だと感じました。

1. AWSサービスについてユースケースや知識を得ることができる

AWSの試験ではユースケースを取り上げ、「どのサービスを利用して、何を目的にするのか」といった問題を長文で聞かれます。
業務でもそういった課題に関してどうやってAWSサービスを利用するかを考える機会が多いためサービス、セキュリティ、料金、サポートについての知識を得ることができることは資格を受けるメリットになると考えています。

2. AWSは常に新しいサービスや機能を追加しており、資格取得を通じて最新の技術トレンドを学び続けることができる

生成AIを利用する際にもある程度のアーキテクチャやイメージを持って利用することは重要だと考えています。
また、生成AIの提案する構成が最新のものであるかはわかりません。
情報の正確性を見極め、自分自身で技術トレンドを把握したうえで生成AIの支援を得ることで、業務を最大限に効率化することが可能と考えています。

まとめ

生成AIの回答はここ数年で大きく進歩していますが、それでもその情報が正しいかどうかを判断するのは人間の役割です。
情報の正確性を見極める力は、生成AIを活用している全ての利用者に今後ますます求められるスキルとなります。 そのため資格を取得するだけではなく実際にその知識を業務で活用し、継続的に学び続けることが重要です。
これからも技術の進化に対応し、常に最新の知識を持ち情報の正確性を見極めるためにも、AWS12冠コンプリートを目指して引き続き頑張りたいと思います。


弥生では一緒に働く仲間を募集しています。 ぜひエントリーお待ちしております。

herp.careers

SageMakerのはじめかた

はじめに

こんにちは。弥生R&D室のsiidaです。R&D室ではSageMakerを使用して機械学習 (ML) のプロジェクトを進めています。SageMakerはMLのための様々な機能が搭載されたサービスであり、データ分析からモデル訓練、ひいてはワークフローの構築まで、SageMakerの中で完結させることができます。

今回はこれまでSageMakerを使ったことがない方向けに、SageMakerのはじめかたについて紹介したいと思います。

SageMakerというと様々なML向けの機能を内包した大きなサービスではありますが、今回はSageMaker Studioを用い、データ分析でおなじみのJupyterを動かすところまで紹介しようと思います。

SageMakerのはじめかた

00_console

まずはAWSのコンソールを開きます。

01_search

次に、検索窓へ "SageMaker" と入れ、出てきた結果の中から "Amazon SageMaker" をクリックします。

02_sagemaker

するとSageMakerのページへ遷移するので、画面左のメニューから "管理者設定" の下の "ドメイン" をクリックします。

03_domain

04_pre_setting

"ドメインを作成" を押すと作成画面が表示されるので、デフォルトの設定のまま "設定" をクリックします。

デフォルトでは "シングルユーザー向けの設定 (クイックセットアップ)" となっており、今回はこちらを使用します。もしネットワークの設定などを細かく決めたい場合には "組織向けの設定" を選択してください。普段のR&D室の業務においても、カスタマイズした設定のものを利用しています。

05_setting

"設定" をクリックすると自動的にセットアップが始まります。数分間待機したのち、SageMaker Domainが作成されます。

※ブログ作成時の一時的なものなので、ドメインとユーザープロファイルをそのまま掲載しています。

06_setting_finish

作成完了後、画面左のメニューから "Applications and IDEs" の下にある "Studio" を選択します。

07_open_studio

ドメインとユーザープロファイルがさきほど作成したものであることを確認し、 "Studioを開く" をクリックします。

08_studio

左上の "Applications" から "JupyterLab" を選択します。

09_jupyter

"Create JupyterLab Space" をクリックし、出現した設定欄にスペースの名前を入力して "Create Space" を押すと、スペースが作成されます。

11_space

その後、インスタンスの種類やストレージの容量などを確認しつつ "Run Space" を押すとインスタンスが立ち上がります。

12_run

13_finish

最後に "Open JupyterLab" を実行すると、無事にSageMaker上でJupyterを実行できました。

※終了する際には、"Stop Space"を押して実行したスペースを停止してください。

まとめ

  • SageMakerを使用するには、まずドメインを作成します。
  • ドメイン作成後 "Applications and IDEs" から "Studio" を選択し、作成したドメインを指定してSageMaker Studioを起動します。
  • SageMaker Studioでは "Applications" から "JupyterLab" を選択し、スペースを作成することでJupyterのインスタンスに接続できます。

本記事は下記の記事と同じ内容です。 アクセス解析を目的としてマルチポストしています。

qiita.com

弥生では一緒に働く仲間を募集しています。 ぜひエントリーお待ちしております。

herp.careers

情報システム部CTLがZuoraオンラインセミナー「お客様事例セッション!」に登壇します

こんにちは、開発本部の かとあず です。
8月27日(火)開催のZuoraオンラインセミナー「お客様事例セッション!成功事例から学ぶZuora活用の実践と成果〜弥生株式会社〜」にCTL(Chief Technical Lead) 山川 和也が登壇します。

Zuoraオンラインセミナー お客様事例セッション!成功事例から学ぶZuora活用の実践と成果〜弥生株式会社〜

Zuora Japan株式会社様が主催のウェブセミナーです。

「お客様事例セッション!」Webinarシリーズでは、Zuoraを導入し顕著な成功を収めた顧客の実践事例を通じて、Zuoraがいかにビジネスの成長を促進し、ゴール達成をサポートし、現場業務を革新的に効率化しているのかをご紹介します。リアルな成功体験を余すところなくお伝えし、業界の先駆者たちが実践する戦略とソリューションを深く理解いただくことで、貴社の次なる成功に向けた貴重な知見とインスピレーションを得る絶好の機会を提供します。

記念すべき第一回目では、弥生株式会社の成功事例を特集します。弥生株式会社は2016年にZuoraを導入し、今年で運用9年目を迎えました。初期導入から段階的にシステムを拡張し、現在ではほぼ全商材をZuoraで一元管理しています。ここに至るまでの道のりや、直面した課題への対応方法、そして実際の成果について、Zuora導入に携わってきた山川和也様からの貴重な体験談をお聞きいただける対談セッションです。

https://info.zuora.com/Saas-Customer-BestPractice-webinar-yayoi.html

日時:2024年8月27日(火)16:00-16:30
講演者:弥生株式会社 開発本部 情報システム部 CTL 山川 和也
インタビュアー:Zuora Japan株式会社 執行役員 Solution Consulting部門担当 谷内 輝男様

参加申し込み

以下のリンクのウェビナー参加申し込みフォームからお申し込みください。 info.zuora.com

情報システム部 CTL 山川さんってどんな人?

山川さんを取り上げている記事をぜひご覧ください。 www.wantedly.com


弥生では一緒に働く仲間を募集しています。
開発生産性を追求しているチームにご興味のある方、ぜひエントリーお待ちしております。
herp.careers

SageMaker Studioの仮想マシンの容量を変更する方法

TL;DR

こんにちは。弥生R&D室のsiidaです。R&D室ではSageMakerを使用して機械学習 (ML) のプロジェクトを進めていますが、SageMakerにはSageMaker Studioというサービスがあり、Web上のUIを通してMLのための環境を構築することができます。

このSageMaker Studioで建てる仮想マシンのデフォルトの容量は100GBが上限なのですが、昨今のLLMはモデルだけでも100GBを超えることが多く、不足気味です。そこで、容量の上限を引き上げる方法をまとめたいと思います。

続きを読む

AWS ECSのCPUアーキテクチャをArmに変更してコスト削減

こんにちは、インフラ/Misocaチームのfuku710です。
MisocaチームではAWSのコスト削減の一環として、ECS上で動いているコンテナアプリケーションのCPUアーキテクチャをArmプロセッサに変更する取り組みを行いました。
その過程でやってきたことや工夫したことなどについて書きたいと思います。

AWS Fargate Gravitonについて

MisocaではECSのコンテナの実行にAWS Fargateを使用しています。
現在FargateではArmアーキテクチャのCPUとしてAWS Graviton2がサポートされており、x86ベースのFargateからGraviton2ベースのFargateに変更することにより約20%のコスト削減が見込めます。

Linux/X86 Linux/ARM
1時間当たりのCPU(vCPU) 0.05056USD 0.04045USD
1時間当たりのメモリ(GB) 0.00553USD 0.00442USD

aws.amazon.com

また、パフォーマンスとしてもx86と比べて最大19%高くなると記述されています。

aws.amazon.com

ECSをArm対応するまでの流れ

ECSにおいてx86で動いているコンテナをArmで動かすためには以下の二つの作業が必要となります。

  • Armアーキテクチャに対応したコンテナイメージを作成する
  • ECSのタスク定義ファイルでCPUアーキテクチャにArmを指定する

ここで肝となるのはコンテナイメージの作成です。
Dockerでは1つのイメージで複数のアーキテクチャに対応したマルチプラットフォームイメージを作成できます。
マルチプラットフォームイメージとしてイメージを作ることにより、コンテナが動作するプラットフォームに応じて自動で適切なイメージが選択されて実行できます。
これにより、ECSのタスク定義でCPUアーキテクチャを指定するだけでArm環境に移行できます。

マルチプラットフォームイメージを作成するための方法はいくつかありますが、1つはQEMUを使ったビルドです。
QEMUはプロセッサエミュレータであり、これを利用してビルドすることによりx86のマシン上でx86のイメージとArmのイメージ両方を作成することができます。
この方法のメリットとしてアーキテクチャごとにマシンを用意する必要がないため、既存のCI/CDの変更を少なくしてイメージの作成が行えます。
しかし、デメリットとしてQEMUはエミュレータであるためイメージによっては非常に時間がかかる可能性があります。

私たちも当初はQEMUを使ったビルドのアプローチをとりましたがビルド時間が増加し、特にRuby on Railsが動くコンテナのビルドではbundle installで非常に時間がかかり、数分で終わっていたビルドが30分近くかかるようになってしまいました。
これでは運用上もコスト上もよろしくないため、アーキテクチャ別の環境を用意してそれぞれの環境でビルドしてマルチプラットフォームイメージを作成するという方針に切り替えました。

MisocaではAWS CodeBuildとGitHub Actionsの2つのサービス上でコンテナイメージをビルドをしていたため、それぞれのサービスで対応した内容を紹介します。

AWS CodeBuild

MisocaではAWS CodePipelineのフロー上でCodeBuildによるビルド/デプロイを行っています。
CodeBuildでは動作するビルド環境のイメージを選択できるため、x86環境のCodeBuildとArm環境のCodeBuildを作成しCodePipelineのビルドステージで2つのCodeBuildを並列に動かすようにします。
ポイントは各環境のビルド後にマルチプラットフォームイメージをプッシュするステージを用意している点です。
ここで各プラットフォームのイメージへの参照しているマルチプラットフォームイメージを作成してプッシュする処理を行います。

マルチプラットフォームイメージを作成するCodePipelineの構成

AWSの構成管理にTerraformを使用しているため、Terraformでの記述を示します。

CodeBuildでArm環境を利用する場合はenvironmenttypeARM_CONTAINERにしたうえでimageで利用可能なイメージを指定します。

Docker images provided by CodeBuild - AWS CodeBuild

CodePipelineでは各環境でビルドした際のイメージ名をマルチプラットフォームイメージをプッシュするCodeBuildに渡すようにします。

resource "aws_codebuild_project" "app_x86_64" {
  /* 省略 */
  environment {
    compute_type                = "BUILD_GENERAL1_MEDIUM"
    image                       = "aws/codebuild/standard:7.0"
    type                        = "LINUX_CONTAINER"
    image_pull_credentials_type = "CODEBUILD"
    privileged_mode             = true
  }
}

resource "aws_codebuild_project" "app_aarch64" {
  /* 省略 */
  environment {
    compute_type                = "BUILD_GENERAL1_SMALL"
    image                       = "aws/codebuild/amazonlinux2-aarch64-standard:3.0"
    type                        = "ARM_CONTAINER"
    image_pull_credentials_type = "CODEBUILD"
    privileged_mode             = true
  }
}

resource "aws_codebuild_project" "push_app" {
  /* 省略 */
}

resource "aws_codepipeline" "pipeline-deploy" {
 /* 省略 */
  stage {
    name = "Build"

    action {
      name            = "BuildDockerImageOnX86_64"
      category        = "Build"
      owner           = "AWS"
      provider        = "CodeBuild"
      version         = "1"
      input_artifacts = ["Source"]
      namespace       = "CodeBuildVariablesX86_64"

      configuration = {
        PrimarySource = "Source"
        ProjectName   = aws_codebuild_project.app_x86_64.name
      }
    }

    action {
      name            = "BuildDockerImageOnAarch64"
      category        = "Build"
      owner           = "AWS"
      provider        = "CodeBuild"
      version         = "1"
      input_artifacts = ["Source"]
      namespace       = "CodeBuildVariablesAach64"

      configuration = {
        PrimarySource = "Source"
        ProjectName   = aws_codebuild_project.app_aarch64.name
      }
    }
  }

  stage {
    name = "Push"

    action {
      name             = "PushToECR"
      category         = "Build"
      owner            = "AWS"
      provider         = "CodeBuild"
      version          = "1"
      input_artifacts  = ["Source"]
      output_artifacts = ["ImageDefinition"]
      namespace        = local.codebuild_namespace

      configuration = {
        ProjectName   = aws_codebuild_project.push_app.name
        PrimarySource = "Source"
        EnvironmentVariables = jsonencode(
          [
            {
              "name" : "X86_64_BUILT_IMAGE_NAME",
              "value" : "#{CodeBuildVariablesX86_64.BUILT_IMAGE_NAME}",
              "type" : "PLAINTEXT"
            },
            {
              "name" : "AARCH64_BUILT_IMAGE_NAME",
              "value" : "#{CodeBuildVariablesAach64.BUILT_IMAGE_NAME}",
              "type" : "PLAINTEXT"
            }
          ]
        )
      }
    }
  }
  /* 省略 */
}

イメージをビルドするbuildspecファイルは共通でuname -mの出力をイメージタグにすることで、アーキテクチャごとに別のタグでECRにプッシュします。

version: 0.2

env:
  exported-variables:
    - BUILT_IMAGE_NAME
phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin $IMAGE_FQDN
      - export BUILT_IMAGE_NAME=$REPOSITORY_URL:$(uname -m)

  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t $BUILT_IMAGE_NAME
      - echo Build completed on `date`

  post_build:
    commands:
      - echo Pushing the Docker image...
      - docker push $BUILT_IMAGE_NAME

マルチプラットフォームイメージをプッシュするbuildspecファイルはdocker buildxを使ってマルチプラットフォームイメージを作成します。
imagetools createコマンドで引数に各プラットフォームのイメージ名、--tagオプションに新しく作成するイメージ名を指定することでマルチプラットフォームイメージがプッシュされます。

version: 0.2

env:
  exported-variables:
    - BUILT_IMAGE_NAME
phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin $IMAGE_FQDN
      - export BUILT_IMAGE_NAME=$REPOSITORY_URL:latest

  build:
    commands:
      - >-
        docker buildx imagetools create
        --tag $BUILT_IMAGE_NAME
        $X86_64_BUILT_IMAGE_NAME
        $AARCH64_BUILT_IMAGE_NAME

GitHub Actions

GitHub Actionsではアプリケーションの共通となるイメージなどを定期的に作成しています。
こちらもCodeBuild同様にアーキテクチャの環境別にビルドをしてマルチプラットフォームイメージを作成したいところです。
実はこれまでGitHubがホストするランナーでArmアーキテクチャに対応しているものはなく、Arm環境上でワークフローを動かしたい場合はセルフホステッドランナーを使い自前でランナーを用意する必要がありました。
しかし、6月の初めからGitHubがホストするランナーとしてArmランナーが提供されるようになり、より手軽にArm環境上でビルドするワークフローを構築できるようになりました。

github.blog

ArmランナーはGitHub Actionsのより大きなランナー(larger runner)という枠組みで提供されており、使用するためにはGitHub Team または GitHub Enterprise Cloudプランである必要があります。
通常のランナーと異なり事前にOrganizationの設定から新しくGitHubホステッドランナーとして追加する必要があります。

docs.github.com

ランナー自体の利用料金は同スペックの場合、標準ランナー$0.008/1minに対してArmランナー$0.005/1minで割安になりますが、より大きなランナーとして管理されるランナーはアカウントに含まれているGitHub Actionsの利用時間(GitHub Teamであれば3000分/月)を使用することができないため、独立して課金されることには注意してください。

Organizationにランナーの追加が完了したら、ワークフローファイルのruns-onプロパティにランナーのラベルを指定することで該当のランナーを使用することができます。

GitHub-hosted runnersの一覧

GitHub Actionsではmatrixを使用することによりジョブを並列に動作することができます。 Dockerのドキュメントには複数のランナーでビルドするワークフローファイルの例がありますが、そこから以下のようにstrategyrun-onを変更してランナーを分けるようにすればx86とArmのランナーそれぞれでビルドすることができます。

  build:
    strategy:
      matrix:
        include:
          - platform: linux/amd64
            runner: ubuntu-latest
          - platform: linux/arm64
            runner: Misoca-Linux-ARM64-runners
    runs-on: ${{ matrix.runner }}

ECSの対応

Arm対応のイメージがビルドできる環境が整ったら、ECSのFargateでGraviton2を利用できるようにします。
これ自体の対応は簡単で、タスク定義ファイルにruntimePlatformプロパティを記述して、operatingSystemFamilyLINUXcpuArchitectureARM64に設定することでコンテナがFargate Gravion上で動作します。

    "runtimePlatform": {
        "operatingSystemFamily": "LINUX",
        "cpuArchitecture": "ARM64"
    },

成果

実際にはSavings Plansなどによる考慮も必要ですが、以下のCost Explorerのグラフを見るとArmに切り替えてから期待通りに時間あたりのコストが下がっていることが確認できます。

また、レスポンスタイムの改善もみられました。
以下のグラフでは実線がArmに切り替えた後のレスポンスタイム、点線がその前の週のレスポンスタイムです。
パフォーマンスの改善はそこまで期待していなかったのでうれしい誤算です。

一方、今回のArm対応により月1回動くバッチ処理の時間が長くなったり、CIの動作が不安定になるといった問題も発生しました。
バッチ処理に関してはx86でのイメージのビルドも残してx86とArmを併用して運用するという方法で解決することにしました。
本来であればArm環境移行後にx86のビルド処理を削除してコストを抑えるつもりだったので残念ですが、マルチプラットフォームイメージとしてイメージを作ったことにより、このような対応が容易にできたのは良かったです。

まとめ

ECSで動いているコンテナをFargateのGraviton2で動かせるように対応した結果、期待以上にコストの削減とパフォーマンスの改善を達成することができました。
しかし、特定の処理でのパフォーマンス悪化やCIでの問題が発生することがあったので、そういったリスクにも注意しながらArm環境への移行を進めたほうがいいでしょう。


また弥生では一緒に働く仲間を募集しています。 ぜひエントリーお待ちしております。

herp.careers