💭

Mac向けMultipassのUbuntu 20.04でLocalStackを使ってみる

2022/02/08に公開

はじめに

WindowsのWLS2と同じような環境を準備するため。[1]
Intel MacBook Pro向けに、Multipassのbuntu 20.04でLocalStack環境の構築する。

https://multipass.run/

環境

  • MacBook Pro 13-inch, 2018
  • macOS Big Sur 11.6.3
  • Homebrew導入済み

導入

multipassインストール

Installing Multipass on macOS | Multipass documentation

brewコマンドでmultipassをインストールする。
バックエンドはhyperkitのまま使用する。[2]

% brew install --cask multipass

VM作成

cloud-initで設定をしてVMを作成する。

ssh-keyを作成する。

% ssh-keygen -t rsa -b 4096 -C "$(uuidgen)" -f ~/.ssh/multipass_docker-vm

cloud-config.yamlを作成する。
基本的な設定を行う。
docker関連、avahi-daemon[3]、LocalStack関連のインストール設定を行う。[4]

cloud-config.yaml
% AUTHORIZED_KEYS=$(cat ~/.ssh/multipass_docker-vm.pub )
% cat > ./cloud-config.yaml << _EOF_
#cloud-config

locale: en_US.UTF8
timezone: Asia/Tokyo

users:
  - name: ubuntu
    sudo: ALL=(ALL) NOPASSWD:ALL
    ssh-authorized-keys:
      - ${AUTHORIZED_KEYS}

package_upgrade: true

packages:
  - avahi-daemon
  - apt-transport-https
  - ca-certificates
  - curl
  - gnupg
  - lsb-release
  - zip
  - jq
  - python3-pip
_EOF_
cat >> ./cloud-config.yaml << '_EOF_'

runcmd:
  - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
  - echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  - apt-get -y update
  - apt-get -yV upgrade
  - apt-get install -y docker-ce docker-ce-cli containerd.io
  - curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  - chmod +x /usr/local/bin/docker-compose
  - [systemctl, daemon-reload]
  - [systemctl, restart, docker, containerd, ssh]
  - usermod -aG docker ubuntu
_EOF_

CPU2個、メモリ4GB、ディスク20GBのマシンにUbuntu20.04をインストールする。
cloud-config.yamlに合わせてセットアップ。

% multipass launch --name docker-vm --cpus 2 --mem 4G --disk 20G --cloud-init cloud-config.yaml 20.04

shellログイン

作成されたVMにログインしてみる。
エラーが出るが未解決。[5]

 % multipass shell docker-vm
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-97-generic x86_64)

〜中略〜

ubuntu@docker-vm:~$ exit
logout

sshログイン

ssh経由でVMにログインしてみる。

 % ssh -i ~/.ssh/multipass_docker-vm ubuntu@docker-vm.local
 he authenticity of host 'docker-vm.local (0000::000:0000:0000:0000%bridge100)' can't be established.
ECDSA key fingerprint is SHA256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'docker-vm.local,0000::000:0000:0000:0000%bridge100' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-97-generic x86_64)

〜中略〜

ubuntu@docker-vm:~$ exit
logout
Connection to docker-vm.local closed.

ssh configに設定を追加してする。

~/.ssh/config
Host docker-vm.local
  HostName docker-vm.local
  IdentityFile ~/.ssh/multipass_docker-vm
  User ubuntu
  Port 22

下記のコマンドでアクセスできるようになる。

% ssh docker-vm.local

アクセス時にエラーが出ない場合は「ssh-keygen -R」コマンドでログイン記録を削除する。

% ssh -i ~/.ssh/multipass_docker-vm ubuntu@docker-vm.local
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:0000000000000000000000000000000000000.
Please contact your system administrator.
Add correct host key in /Users/hoge/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/hoge/.ssh/known_hosts:6
ECDSA host key for docker-vm.local has changed and you have requested strict checking.
Host key verification failed.
% ssh-keygen -R docker-vm.local

また、時間が経つとdocker-vm.localでアクセスできなくなる?VMを立ち上げ直すと接続できる。

各種コマンド

VM状態一覧

VMの状態一覧が表示される。

% multipass ls
Name                    State             IPv4             Image
docker-vm               Running           192.168.64.2     Ubuntu 20.04 LTS
                                          172.17.0.1

VM個別情報

VMの個別情報が表示される。
「multipass info docker-vm --format json」にするとjson形式で出力されるようになる。

% multipass info docker-vm
Name:           docker-vm
State:          Running
IPv4:           192.168.64.2
                172.17.0.1
Release:        Ubuntu 20.04.3 LTS
Image hash:     60c005e96488 (Ubuntu 20.04 LTS)
Load:           0.01 0.03 0.05
Disk usage:     2.0G out of 19.2G
Memory usage:   188.7M out of 3.8G
Mounts:         --

VM停止

VMを停止する。

% multipass stop docker-vm
% multipass list          
Name                    State             IPv4             Image
docker-vm               Stopped           --               Ubuntu 20.04 LTS

VM起動

VMを起動する。[6]

% multipass start docker-vm
% multipass list           
Name                    State             IPv4             Image
docker-vm               Running           192.168.64.2     Ubuntu 20.04 LTS
                                          172.17.0.1

VM削除

deleteコマンドでゴミ箱に移動する。
purgeコマンドでゴミ箱を空にする。

% multipass delete docker-vm
% multipass ls              
Name                    State             IPv4             Image
docker-vm               Deleted           --               Not Available
% multipass purge
% multipass ls   
No instances found.

フォルダーのマウントとアンマウント

マウント元のフォルダーとファイルを作成する。

% mkdir ~/ubuntu 
% touch ~/ubuntu/hogehoge 

multipass内にマウント先を作成しておく。

% multipass shell docker-vm
ubuntu@docker-vm:~$ mkdir ubuntu
ubuntu@docker-vm:~$ exit

マウント元「/Users/hoge/ubuntu」をマウント先「/home/ubuntu/ubuntu」へマウントする。

% multipass mount ~/ubuntu docker-vm:~/ubuntu            
% multipass info docker-vm                               
Name:           docker-vm
State:          Running
IPv4:           192.168.64.2
                172.17.0.1
Release:        Ubuntu 20.04.3 LTS
Image hash:     3d7282d3e92b (Ubuntu 20.04 LTS)
Load:           0.13 0.08 0.04
Disk usage:     5.0G out of 19.2G
Memory usage:   468.9M out of 3.8G
Mounts:         /Users/hoge/ubuntu => ~/ubuntu
                    UID map: 501:default
                    GID map: 20:default

マウントされていることを確認する。

% multipass shell docker-vm
ubuntu@docker-vm:~$ ls ubuntu/
hogehoge
ubuntu@docker-vm:~$ exit

アンマウントする。

% multipass umount docker-vm                 
% multipass info docker-vm 
Name:           docker-vm
State:          Running
IPv4:           192.168.64.2
                172.17.0.1
Release:        Ubuntu 20.04.3 LTS
Image hash:     3d7282d3e92b (Ubuntu 20.04 LTS)
Load:           0.06 0.06 0.03
Disk usage:     5.0G out of 19.2G
Memory usage:   460.5M out of 3.8G
Mounts:         --

LocalStack準備

Dockerの起動テスト

Dockerでhello-worldを実行できるか確認する。

% multipass shell docker-vm
ubuntu@docker-vm:$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete 
Digest: sha256:507ecde44b8eb741278274653120c2bf793b174c06ff4eaa672b713b3263477b
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
〜後略〜

docker-compose.ymlを準備する

LocalStackをGitHubからダウンロードして解凍する。[7]

ubuntu@docker-vm:$ curl -L -O https://github.com/localstack/localstack/archive/refs/tags/v0.13.0.zip
ubuntu@docker-vm:$ unzip v0.13.0.zip

docker-compose.ymlを編集する

ubuntu@docker-vm:$ vi localstack-0.13.0/docker-compose.yml

変更点
v0.13.1に固定。Pro用の設定を削除。IP設定(127.0.0.1:)削除[8][9]。Lambda用設定のLAMBDA_EXECUTORを追加。[10]

docker-compose.yml 編集後の状態
version: "3.8"

services:
  localstack:
    container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
    image: localstack/localstack:0.13.1
    network_mode: bridge
    ports:
      - "4566:4566"
      - "4571:4571"
    environment:
      - SERVICES=${SERVICES- }
      - DEBUG=${DEBUG- }
      - DATA_DIR=${DATA_DIR- }
      - LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }
      - LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY- }  # only required for Pro
      - HOST_TMP_FOLDER=${TMPDIR:-/tmp/}localstack
      - DOCKER_HOST=unix:///var/run/docker.sock
      - LAMBDA_EXECUTOR=docker-reuse
    volumes:
      - "${TMPDIR:-/tmp}/localstack:/tmp/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"

docker-compose.ymlの編集を保存して終了する。(viだとescキーを押す。「:wq」を入力してエンターキーを押す。)

起動する

docker-composeを使って起動する。[11]

ubuntu@docker-vm:$ cd localstack-0.13.0
ubuntu@docker-vm:~/localstack-0.13.0$ docker-compose up -d
Pulling localstack (localstack/localstack:)...
a10c77af2613: Pull complete
 〜中略〜 
Digest: sha256:3fcef2507cd96b64a5efd94ab25e95fa58b46e97c1217e3c0e3cec352d8376ee
Status: Downloaded newer image for localstack/localstack:0.13.1
Creating localstack_main ... done

起動状況を確認をする。

ubuntu@docker-vm:~/localstack-0.13.0$ docker-compose ps
     Name               Command          State                                              Ports
---------------------------------------------------------------------------------------------------------------------------------------------
localstack_main   docker-entrypoint.sh   Up      0.0.0.0:4566->4566/tcp,:::4566->4566/tcp, 0.0.0.0:4571->4571/tcp,:::4571->4571/tcp, 5678/tcp

[ex] docker-composeを使って停止する。

ubuntu@docker-vm:~/localstack-0.13.0$ docker-compose down

サービスの起動状況チェック

LocalStackで使用できるサービスの起動状況を確認する。[12]

ubuntu@docker-vm:~/localstack-0.13.0$ curl -s http://localhost:4566/health | jq
{
  "features": {
    "initScripts": "initialized"
  },
  "services": {
    "acm": "available",
    "apigateway": "available",
    "cloudformation": "available",
    "cloudwatch": "available",
    "config": "available",
    "dynamodb": "available",
    "dynamodbstreams": "available",
    "ec2": "available",
    "es": "available",
    "events": "available",
    "firehose": "available",
    "iam": "available",
    "kinesis": "available",
    "kms": "available",
    "lambda": "available",
    "logs": "available",
    "redshift": "available",
    "resource-groups": "available",
    "resourcegroupstaggingapi": "available",
    "route53": "available",
    "route53resolver": "available",
    "s3": "available",
    "secretsmanager": "available",
    "ses": "available",
    "sns": "available",
    "sqs": "available",
    "ssm": "available",
    "stepfunctions": "available",
    "sts": "available",
    "support": "available",
    "swf": "available"
  }
}

LocalStackへアクセスする

AWS CLI Version 2セットアップ

awscliをダウンロードをしてインストールする。[13]

ubuntu@docker-vm:~$ cd
ubuntu@docker-vm:~$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
ubuntu@docker-vm:~$ unzip awscliv2.zip
ubuntu@docker-vm:~$ sudo ./aws/install
ubuntu@docker-vm:~$ aws --version
aws-cli/2.4.16 Python/3.8.8 Linux/5.4.0-99-generic exe/x86_64.ubuntu.20 prompt/off
ubuntu@docker-vm:~$ rm -fr aws
ubuntu@docker-vm:~$ rm awscliv2.zip

awscli-localをインストールする。

ubuntu@docker-vm:~$ pip3 install awscli-local

コマンドが実行できるようにPATHを通す。

ubuntu@docker-vm:~$ echo 'export PATH="$PATH:~/.local/bin"' >> ~/.bashrc
ubuntu@docker-vm:~$ source ~/.bashrc

LocalStack接続用のダミー設定を作る。

ubuntu@docker-vm:~$ aws configure --profile=localstack
AWS Access Key ID [None]: dummy
AWS Secret Access Key [None]: dummy
Default region name [None]: ap-northeast-1
Default output format [None]: json

S3

作成したバケットや追加したファイルは「docker-compose down」すると消えます。[14]

hoge-bucketバケットを作成する。

ubuntu@docker-vm:~$ awslocal s3 mb s3://hoge-bucket --profile=localstack
make_bucket: hoge-bucket

hoge-bucketバケットが作成されていることを確認する。

ubuntu@docker-vm:~$ awslocal s3 ls --profile=localstack
2020-09-02 22:36:16 hoge-bucket

hoge-bucketバケットにファイル追加と確認をする。

ubuntu@docker-vm:~$ echo 'Test Hoge Hoge!' > hoge.txt
ubuntu@docker-vm:~$ awslocal s3 cp hoge.txt s3://hoge-bucket --profile=localstack
upload: ./hoge.txt to s3://hoge-bucket/hoge.txt
ubuntu@docker-vm:~$ awslocal s3 ls s3://hoge-bucket --profile=localstack
2020-09-02 22:38:45         16 hoge.txt

Lambda

Lambda Functionの準備

コードを作成します。

ubuntu@docker-vm:~$ vi myFunction.py

S3で作った「hoge-bucket」バケットあることが前提のコードになっています。[15]

myFunction.py
import os
import boto3
from boto3.session import Session
from datetime import datetime

session = Session(
    aws_access_key_id='dummy',
    aws_secret_access_key='dummy',
    region_name='ap-northeast-1'
)

if os.getenv('LOCALSTACK_HOSTNAME') is None:
    endpoint = 'http://localhost:4566'
else:
    endpoint=f"http://{os.environ['LOCALSTACK_HOSTNAME']}:4566"

s3 = session.resource(
    service_name='s3', 
    endpoint_url=endpoint
)

def lambda_handler(event, context):

    bucket = 'hoge-bucket'
    key = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + '.txt'
    file_contents = 'Python Lambda Save File'

    s3.Bucket(bucket).put_object(Key=key, Body=file_contents)

    return 'create file '+ key

myFunction.pyの編集を保存して終了する。(viだとescキーを押す。「:wq」を入力してエンターキーを押す。)

zip形式で圧縮をする。

ubuntu@docker-vm:~$ zip lambda.zip myFunction.py

Lambdaへの登録と実行

Functionを登録する。[16]

ubuntu@docker-vm:~$ awslocal lambda create-function --function-name myFunction  --runtime python3.8 --handler myFunction.lambda_handler --role r1  --zip-file fileb://lambda.zip --profile=localstack
{
    "FunctionName": "myFunction",
    "FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:myFunction",
    "Runtime": "python3.8",
    "Role": "r1",
    "Handler": "myFunction.lambda_handler",
    "CodeSize": 592,
    "Description": "",
    "Timeout": 3,
    "LastModified": "2020-10-03T08:20:15.032+0000",
    "CodeSha256": "SuHNSoLMS/zBPGAKiezjN/qL10Nntx2b3o5Z3SSivWY=",
    "Version": "$LATEST",
    "VpcConfig": {},
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "a8380dc0-349f-4be4-949c-065a90431750",
    "State": "Active",
    "LastUpdateStatus": "Successful",
    "PackageType": "Zip",
    "Architectures": [
        "x86_64"
    ]
}

Functionを実行する。[17]

ubuntu@docker-vm:~$ awslocal lambda invoke --cli-binary-format raw-in-base64-out --function-name myFunction --profile=localstack result.log
ubuntu@docker-vm:~$ cat result.log | jq
"create file2020-10-02-08-35-49.txt"

S3にファイルが追加されているか確認する。

ubuntu@docker-vm:~$ awslocal s3 ls s3://hoge-bucket --profile=localstack
2020-10-02 08:35:49         23 2020-10-02-08-35-49.txt

参考にしたサイト

脚注
  1. WSL2上のUbuntu 20.04でLocalStackを使ってみる ↩︎

  2. 設定でvirtualboxに変更できる ↩︎

  3. hostnameでアクセスできるように ↩︎

  4. awcliv2やsawslocalもここでまとめてインストールすることもできる ↩︎

  5. Message from syslogd@docker-vm at Feb 1 09:00:00 ...
    kernel:[ 116.069611] do_IRQ: 0.40 No irq handler for vector ↩︎

  6. VMが起動していない場合に「multipass shell docker-vm」すると。vm起動後にshellへログインできる ↩︎

  7. docker-compose.ymlが必要なだけなので他の取得方法でも良い。 ↩︎

  8. localhostではなくIP指定でアクセスする必要がある。shellでIPアドレスは「ip addr」で確認できる。 ↩︎

  9. さらに別のPCからアクセスしたい場合はポートフォワードとファイアウォールの設定が必要。WSL2で起動したサーバーに外部の端末からアクセスする – GUNMA GIS GEEK ↩︎

  10. AMBDA_DOCKER_NETWORK=hostを設定すると「listen tcp :9001: bind: address already in use」エラーになる。 ↩︎

  11. docker-compose up」を「-d」なしで起動するとログが確認できる。 ↩︎

  12. サービスが起動するまで時間がかかりエラーになることもある。その場合は少し時間を空けてアクセスする。 ↩︎

  13. Linux での AWS CLI バージョン 2 のインストール、更新、アンインストール - AWS Command Line Interface ↩︎

  14. 永続化する設定もある。 LocalStackに保存するデータを永続化する - CLOVER🍀 ↩︎

  15. Lambda functionからS3やDynamoDBにアクセスする場合はos.environ['LOCALSTACK_HOSTNAME']でホスト名取得してendpointを設定する必要がある。 ↩︎

  16. --handler myFunction.lambda_handlerはファイル名.ファンクション名で指定する必要がある。 ↩︎

  17. 初回はdocker imageのダウンロードが走るため起動まで少し時間がかかる。 ↩︎

Discussion