RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

GitLab で AWS Lambda を自動デプロイしてみる

こんにちは、uemura_rks です。
個人的な勉強目的で GitLab 上で AWS Lambda のデプロイを自動化してみました。
GitLab での CICD や AWS SAM、あとは Docker に興味を持っている方に向けて、その構築履歴を紹介したいと思います。
基本的には各ツールのドキュメントを参照しつつ、追記した設定などを共有していきます。

作りたいもの

ローカルに Docker で GitLab や GitLab Runner を立てつつ、プッシュしたら AWS 上に自動デプロイが走る構成を目指します。

  1. GitLab に push したら GitLab Runner が走る。
  2. GitLab Runner から ジョブ実行用コンテナを起動。
    コンテナには AWS SAM CLI が使えるイメージを利用します。
  3. AWS SAM CLI を使って Lambda 本体や AWS リソースを定義した Stack をデプロイ。

1.GitLab 構築

参考:GitLab Docker images | GitLab

さっそく GitLab の構築からはじめていきます。
Docker 上に構築するので、参考ドキュメントのdocker-compose.ymlの部分をベースとして拝借していきます。

version: '3'

services:
  gitlab:
    container_name: gitlab
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'local-gitlab'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://local-gitlab:8929'
    ports:
     - '80:8929'
    volumes:
     - ./gitlab/config:/etc/gitlab
     - ./gitlab/logs:/var/log/gitlab
     - ./gitlab/data:/var/opt/gitlab
    shm_size: '2gb'

ドキュメントでは エンタープライズ版の gitlab-ee イメージを指定していますが、
今回は個人利用なのでコミュニティ版のgitlab-ceを使います。

volumes:セクションに関して、フォルダ構成はこんな感じにしています

$ tree
├── gitlab             (GitLab の volume)
├── gitlab-runner      (GitLab Runner の volume とする予定)
├── docker-compose.yml
└── sampleapp          (サンプルアプリを入れる予定)

一度立ち上げてみます

docker-compose up -d

名前解決できるようにローカルマシンの hosts ファイルに

127.0.0.1 local-gitlab

を追記すると GitLab( http://local-gitlab/ ) でアクセス出来るようになります。

初回は root ユーザでログインすることになりますが、
root のパスワードはこちらのコマンドで知ることが出来ます。

# Visit the GitLab URL, and sign in with the username root and the password from the following command:
sudo docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password

2.GitLab Runner 構築

参考:Run GitLab Runner in a container

こちらもドキュメントに載っている docker run コマンドを参考に、docker-compose.ymlに起こしていきます。

version: '3'

networks:
  gitlab-network:
    name: gitlab-network
    driver: bridge

services:
  gitlab:
    container_name: gitlab
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'local-gitlab'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://local-gitlab:8929'
    ports:
     - '80:8929'
    volumes:
     - ./gitlab/config:/etc/gitlab
     - ./gitlab/logs:/var/log/gitlab
     - ./gitlab/data:/var/opt/gitlab
    shm_size: '2gb'
    networks:
      - gitlab-network
  
  runner:
    container_name: gitlab-runner
    image: gitlab/gitlab-runner:latest
    restart: always
    volumes:
      - ./gitlab-runner/config:/etc/gitlab-runner
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - gitlab-network

ついでに内部ネットワークを作成して、二つのコンテナを同じネットワークに入れておきます。

GitLab Runner の登録

GitLab Runner コンテナも立ち上げたら、GitLab に Runner を登録していきます。

登録トークン取得

参考:Registering runners (deprecated) | GitLab

Runner の登録に入る前に GitLab の登録トークンというものを取得しておきます。
GitLab にリポジトリを作ると、リポジトリSettings > CI/CD > Runnersから GitLab Runner の登録時に必要な「GitLab の URL」と「登録トークン」が取得できます。

注意点として、今紹介している登録トークンを使った方法は、現在の GitLabバージョン15.6 では deprecated となっております。
新しく認証トークンによる登録ができるようになる予定みたいですが、現在はまだ登録トークンを使うしかないのでそのまま進めます。(絶妙にタイミングが悪かったです。)

登録コマンドの実行

参考:one-line-registration-command

Runner の登録に必要な URL と登録トークンが確認できたので、GitLab Runner コンテナに入って register コマンドを実行していきます。

gitlab-runner register \  
    --non-interactive \  
    --url "http://local-gitlab:8929/" \  
    --registration-token "PROJECT_REGISTRATION_TOKEN" \  
    --executor "docker" \  
    --docker-image alpine:latest \  
    --description "docker-runner" \  
    --docker-network-mode gitlab-network
  • --url:docker ネットワーク内の通信になるので、コンテナポートを付け足しておきます。
  • --docker-image:後に作成する.gitlab-ci.ymlにコンテナイメージを指定しなかった場合のデフォルトになるみたいです。今回は使う予定がないのでサンプルのまま登録しています。
  • --docker-network-mode:docker-compose.yml で用意したネットワークを指定しておきます。

登録に成功すると GitLab に「Available specific runners」が増えています。

3.Lambda 環境構築

GitLab Runner の構築までできたので、次は Lambda を用意していきます。
「Lambda のデプロイを自動化する」というゴールから考えると Lambda 単体で試してもよかったのですが、 前から興味があったという理由で今回は AWS SAM を使ってみます。
この投稿では触れませんが、AWS SAM はローカル環境も手に入るのが良いです。

AWS SAM チュートリアル

参考:チュートリアル: Hello World アプリケーションのデプロイ - AWS Serverless Application Model

チュートリアルHello World アプリケーションをデプロイしてみます。
API Gateway と Lambda ですね。

チュートリアルの #Step 1 をローカルで実行します。

#Step 1 - Download a sample application
sam init

すると、「hello world」と出力するだけの Lambda 関数とインフラ定義ファイルの template.yml が作成されます。

一度この状態でローカルからデプロイしてみます。

#Step 2 - Build your application
cd sam-app
sam build

 
#Step 3 - Deploy your application
sam deploy --guided

dry-run の結果を教えてくれます。

Waiting for changeset to be created..
CloudFormation stack changeset
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                     LogicalResourceId                             ResourceType                                  Replacement                                 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                         HelloWorldFunctionHelloWorldPermissionProd    AWS::Lambda::Permission                       N/A                                         
+ Add                                         HelloWorldFunctionRole                        AWS::IAM::Role                                N/A                                         
+ Add                                         HelloWorldFunction                            AWS::Lambda::Function                         N/A                                         
+ Add                                         ServerlessRestApiDeploymentxxxxxxxxxx         AWS::ApiGateway::Deployment                   N/A                                         
+ Add                                         ServerlessRestApiProdStage                    AWS::ApiGateway::Stage                        N/A                                         
+ Add                                         ServerlessRestApi                             AWS::ApiGateway::RestApi                      N/A                                         
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:000000000000:changeSet/samcli-deploy0000000000/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: 

AWS SAM は CloudFormation を拡張したサービスらしいので、メッセージに CloudFormation という単語がちょくちょく出てきますね。

問題ないので「Deploy this changeset? 」に y で答えてデプロイを実行します。

無事に CloudFormation に Stack ができています。
Lambda や API Gateway を個別に見に行ってもちゃんとできています。

デプロイできたので、curl を叩いて hello world が返ってくることを確認しておきます。

$ curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello
{"message": "hello world"}

4.デプロイ自動化

参考:GitLab CI/CD を使用したデプロイ - AWS Serverless Application Model

AWS SAM だけでも1コマンドでデプロイできるようになるので十分便利なのですが、極力人の操作を減らしたいです。
GitLab Runner を使って、プッシュしたら自動で SAM アプリがデプロイされるようにしていきます。

#Step 2 - Build your application
cd sam-app
sam build

 
#Step 3 - Deploy your application
sam deploy --guided

先ほど手で実行した↑の部分が CI/CD 部分ということで、ここを.gitlab-ci.ymlに切り出します。

image: public.ecr.aws/sam/build-python3.9

stages:
  - build
  - deploy

job_build:
  stage: build
  script:
    - cd sam-app
    - sam build

job_deploy:
  stage: deploy
  variables:
      GIT_CLEAN_FLAGS: none
  script: 
    - cd sam-app
    - sam deploy --no-confirm-changeset --no-fail-on-empty-changeset

GitLab Runner のジョブ実行用コンテナには AWS が提供しているイメージを利用します。
AWS SAM CLI が最初から入っているので助かります。

また、ジョブ実行時に利用される IAM のアクセスキーなどを GitLab の Variables に登録しておきます。
参考:Deploying AWS Lambda function using GitLab CI/CD | GitLab

リポジトリSettings > CI/CD > Variablesから登録できます。

あとは、.gitlab-ci.ymlをプッシュすれば GitLab Runner ジョブが立ちあがるようになります。

5.自動デプロイの確認

AWS SAM の Lambda と テンプレートをいじって push→deploy してみます。

Lambda の変更

Hello World アプリケーションで元々コメントアウトされていたグローバルIP取得の処理を アンコメントしてみます。

import json
import requests

def lambda_handler(event, context):
~~~
~~~
    try:
        ip = requests.get("http://checkip.amazonaws.com/")
    except requests.RequestException as e:
        # Send some context about this error to Lambda Logs
        print(e)

        raise e

    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world",
            "location": ip.text.replace("\n", "") // ★ IP出力部分をアンコメント
        }),
    }

テンプレートの変更

参考:FunctionUrlConfig - AWS Serverless Application Model

API Gateway を破棄して、代わりに Lambda の 関数 URL をエンドポイントとして用意してみます。

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      FunctionUrlConfig:
        AuthType: NONE

Outputs:
  HelloWorldFunctionUrlEndpoint:
    Description: "Hello World Lambda Function URL Endpoint"
    Value: !GetAtt HelloWorldFunctionUrl.FunctionUrl

Properties:Events:セクションで定義されていた API Gateway を 関数 URL の設定に置き換えています。

変更が終わったので、プッシュして、GitLab の Pipeline が走ることを確認します。

Pipeline job の実行ログ

無事に Pipeline が走って、

  • Lambda Function → Modify
  • Function URL → Add
  • API Gateway → Delete

されています。

最後に確認として変更後のエンドポイントに curl してみます。

$ curl https://xxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/
{"message": "hello world", "location": "3.115.88.55"}

IPアドレスも返ってきました。

終わりに

ひとまず GitLab + GitLab Runner + AWS SAM という構成で、プッシュしたものを AWS 上に自動でデプロイする土台は作ることができました。
昔、Lambda をマネジメントコンソールから毎回アップロードしていたことがあったので、今後はその手間から解放されそうです。
また、私は Docker についても最近触り始めたばかりなのですが、「GitLab + GitLab Runner」という構成は複数コンテナを組み合わせた構成ということもあって、Docker 初学者にとって良い練習教材になりました。

実業務では自動デプロイだけでなく UT や SAST など自動テストの考慮も必要になると思います。
それらと今回作ってみた構成の相性については、別途検証が必要かなと考えています。

参考

公式ドキュメント以外で参考にさせていただいたブログです。

Dockerコンテナでgitlabとgitlab-runnerを構築してCI/CD | SyachikuLOG


エンジニア中途採用サイト
ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っております!
ご興味ありましたら是非ご確認をお願いします。
20210916153018
https://career-recruit.rakus.co.jp/career_engineer/

カジュアル面談お申込みフォーム
どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。
以下フォームよりお申込みください。
rakus.hubspotpagebuilder.com

ラクスDevelopers登録フォーム
20220701175429
https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/

イベント情報
会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください!

◆TECH PLAY
techplay.jp

◆connpass
rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.