Docker 環境を作るなら Ubuntu のクロスプラットフォームな仮想化ツール Multipass を使おう
はじめに
Web アプリケーションを開発する際、バックエンドの API サーバーやデータベースなどの複数のマシン環境を1台の PC で動かすことの可能なコンテナツールとして、Docker は広く利用されています。
この便利な Dockerですが、複数人で Web アプリケーションを開発しているチームで各メンバの開発用 PC の OS が異なる状態(例えば、A さんが Windows、B さんが macOS など)で、Docker をローカル環境に直接インストールしていた場合、下記のような不都合が発生します。
- Docker のバージョンがメンバ間で統一されていない 😱
- コンテナ外で使用必須のツールのインストール方法・バージョンがメンバ間で異なる 😱
- コンテナ外で使用必須のシェルスクリプトは OS 毎で(または OS の差異を考慮して)作成する必要がある 😱
以上の問題は、Docker ホスト環境が 各 OS へ依存してしまっていることが原因です。
特に、3.のケースは Unix系の OS と Windows の場合、 Bash と PowerShell の shell の違いやファイルパス表記方法の違いのギャップが大きく苦しむことになります。この問題は、Python や Node.js などでバッチを作成することで、処理やファイルパスの違いを吸収することができますが、一方、 2.の問題が発生するため良い解決策とは言えません。
この問題の解決策として、有効なのが Linux の仮想環境上に Docker をインストールする[1]ことで、複数の OS 依存性を特定の Linux OS にのみに限定する方法です。有名な構成としては、Vagrant + VirtualBox + Docker がよく知られています。Vagrant は、CLIで仮想環境の作成が可能で、環境の初期化時設定をコードとして管理可能な IaC (Infrastructure as Code)が可能な点が優れています。
しかしながら今現在、仮想化ツールの VirtualBox は Apple Silicone (いわゆる M1/M2/M3 Mac など)の PC では正式には動作しないという問題があります。
このため、下記の条件を満足する仮想化ツールとして白羽の矢が立ったのが Ubuntu 環境のクロスプラットフォームな仮想化ツールである Multipass です。
- Apple Silicone の macOS 環境で動作可能
- CLI のみで仮想環境構築が可能
- Cloud-init による IaC が可能
本記事では、Multipass を使用したクロスプラットフォームな Docker 開発環境構築の方法について紹介します。
この記事を読んで欲しい人
- 各メンバの開発用 PC の OS が異なるチームで、クロスプラットフォームな Docker のローカル開発環境を構築したい人
- Multipass 初心者で基本的な使い方を学びたい人
- 商用利用可能かつ無料の Docker 環境が欲しい人(Docker Desktop からの移行)
前提知識
本記事は下記についての基礎的な知識を前提として話を進めます。(Linux や Docker に全く触ったことがないという人にはハードルが高いと思います。)
- CLI (シェル)の操作
- ssh 接続
- Docker
- VSCode
Multipass とは?
Multipass は Debian 系 Linux ディストリビューションである Ubuntu 限定で仮想マシンを提供してくれるツールです。
Multipass の特徴としては、シンプルなコマンドを使用し CLI 上で仮想マシンを作成することが可能という点です。Windows・Mac・Linux 環境で動作することはもちろん Apple Silicone Mac(いわゆる M1/M2/M3 Mac)でも、Rosetta2 の利用なしに動作します。
また、yaml 形式の Cloud-init というファイルに仮想マシンの設定やパッケージのインストールを記述しておくことで、仮想マシン作成時のセットアップ作業を自動化可能です。
Multipass のインストール
お使いの環境の手順を参照して、Multipass をインストールします。
macOS 環境向けインストール手順
macOS 向けの Multipass のインストール方法について、説明します。
brew によるインストール
Multipass のインストールは Mac向けのパッケージマネージャである Homebrew が利用できることを前提とします。もし、まだ導入されてなければ下記ページからインストールを実施してください。
brew install --cask multipass
下記のコマンドで multipass のインストール確認を実施します。
バージョン情報が表示されれば正しくインストールされています。
multipass --version
アクティビティモニターを起動して、multipassd
が起動しているか確認をして下さい。
もし、起動が確認できない場合は PC の再起動を試してみて下さい。
アクティビティモニタ
brew によるバージョン更新
必要に応じて、Multipass のバージョン更新を実施します。作成した既存の仮想環境は新しいバージョンでも引き続き利用できます。
brew upgrade multipass
brew によるアンインストール
brew uninstall multipass
(参考)Mac 著者環境
カテゴリ | 内容 |
---|---|
OS | macOS Sonoma 14.3.1 |
チップ | Apple M1 |
メモリ | 16GB |
ストレージ | 512GB |
Multipass | 1.13.1+mac |
Windows 環境向けインストール手順
ドライバのインストール
Windows 環境で Multipass を動作させるには Hyper-V または VirtualBox が必要ですので、下記記事を参考にインストールを実施して下さい。デフォルトのドライバは Hyper-V で設定されており、 Hyper-V は Microsoft 製であることから Windows 環境との相性を考えると VirtualBox よりも Hyper-V の導入を個人的に推奨します。
Windows11 Home 向けユーザーの Hyper-V インストール手順は下記を参照をして下さい。
winget のインストール
winget は Windows 標準のパッケージマネージャです。
winget が環境にインストールされているかどうかは下記のコマンドで確認します。
バージョン情報が表示されればすでにインストールされています。
winget --version
コマンドが見つからなかった場合は下記ページの「winget をインストールする」に従って winget
のインストールを実施して下さい。
PowerShell7 のインストール
システム内蔵の Windows PowerShell を使用している場合は、新しい PowerShell7.x を利用するよう推奨してくるため、PowerShell のインストールを行います。
バージョン情報が7.xで正しく表示されれば、すでに新しい PowerShell を利用しています。
pwsh --version
コマンドが見つからなった場合は下記のコマンドでインストールします。
winget install --id Microsoft.Powershell --source winget
インストール確認は下記のコマンドで実施します。
以降の PowerShell の操作は PowerShell7 を使うことを推奨します。
winget によるインストール
winget install -e --id Canonical.Multipass
Multipass のインストール確認は下記コマンドで実施します。
正しくインストールされている場合は、Multipass のバージョン情報が表示されます。
multipass --version
winget によるアップデート
必要に応じて、Multipass のバージョン更新を実施します。
winget upgrade -e --id Canonical.Multipass
マウント機能の有効化
On Windows mounts are disabled by default, as anyone with TCP access to localhost (127.0.0.1) can use Multipass, and by extension, gets access to the whole file system.
マウントとは、仮想環境のディレクトリに、ローカル環境のディレクトリを紐付けることで、仮想環境からローカル環境上のファイルをアクセス可能にし、ファイルの変更を両環境で同期する機能です。
公式記事によると Windows 環境で mount 機能の有効化は localhost からローカル環境のファイルシステム全体にアクセスできてしまうリスクがあります。
この点について注意をしてマウント機能の有効化を実施して下さい。有効化後は Multipass のサービスを再起動して下さい。
下記コマンドは PowerShell を管理者として実行して下さい。
# 確認
multipass get local.privileged-mounts
# 変更
multipass set local.privileged-mounts=Yes
# 変更確認
multipass get local.privileged-mounts
# サービス再起動
Restart-Service -Name multipass
VirtualBox をドライバとする場合の設定変更
VirtualBox を使う場合は Hyper-V がデフォルトのドライバとなっているので変更が必要です。
# 確認
multipass get local.driver
# 変更
multipass set local.driver=virtualbox
# 変更確認
multipass get local.driver
Hyper-V に戻す場合は下記のコマンドを実施して下さい。
# 確認
multipass get local.driver
# 変更
multipass set local.driver=hyperv
# 変更確認
multipass get local.driver
winget によるアンインストール
winget uninstall multipass
(参考)Windows 著者環境
カテゴリ | 内容 |
---|---|
OS | Windows11 Pro |
チップ | Intel i5-12600KF |
メモリ | 32GB |
ストレージ | 1TB |
Multipass | 1.13.1+win |
Linux 環境向けインストール手順
基本は下記の公式ドキュメントを参照して下さい。ハマりポイントなどがあれば後から追記しようかと思います。
ワンライナーで仮想環境作成
デフォルト仮想環境 primary の作成
とにかく細かい設定は良いので、すぐに Ubuntu の仮想環境が欲しい場合は、下記のコマンドで Multipass で予約されているデフォルト仮想環境 primary を作成可能です。
このコマンドで仮想環境の作成終了後すぐに、デフォルトユーザーubuntu
としてshell ログインできます。
multipass shell
shell ログインできたら、ls
コマンドを実行してみるとディレクトリHome
が作成されています。
cd Home
をすると、 なんとローカル環境のホームディレクトリに移動でき、ローカル環境のファイルにアクセスできる状態になっています。
ubuntu@primary:~$ ls
Home snap
ubuntu@primary:~$ cd Home
ubuntu@primary:~/Home$ ls
AWSCLIV2.pkg Desktop Downloads Movies Pictures config python3
Applications Documents Library Music Public python
仮想環境を出るにはexit
を実行します。
ubuntu@primary:~$ exit
logout
multipass shell 0.10s user 0.07s system 0% cpu 10:08.33 total
仮想環境の情報について確認
multipass info
で仮想環境の情報を確認できます。複数の環境が作成されている場合は、その環境情報についても表示されます。
multipass info
Name: primary
State: Running
Snapshots: 0
IPv4: 192.168.64.230
Release: Ubuntu 22.04.4 LTS
Image hash: edba2f9aad6f (Ubuntu 22.04 LTS)
CPU(s): 1
Load: 0.00 0.00 0.00
Disk usage: 1.6GiB out of 4.8GiB
Memory usage: 149.0MiB out of 962.4MiB
Mounts: /Users/<user name> => Home
UID map: 501:default
GID map: 20:default
デフォルト仮想環境 primary は、CPU: 1、ディスクサイズ: 5GB、メモリ: 1GB の設定でリソースが割り当てられたことが確認できます。
Mounts:
を見ると、ローカル環境のホームディレクトリが仮想環境上のHome
ディレクトリに対応づいていることが確認できます。このために、仮想環境上からローカル環境のファイルにアクセスが可能になっていました。
環境名を指定して情報を取得する場合は下記のコマンドで実施します。
multipass info primary
# multipass info <仮想環境名>
仮想環境の起動・停止・再起動
起動
multipass start primary
# multipass start <仮想環境名>
停止
multipass stop primary
# multipass stop <仮想環境名>
ubuntu@primary:~$ sudo shutdown now
再起動
multipass restart primary
# multipass restart <仮想環境名>
ubuntu@primary:~$ sudo reboot
仮想環境の削除
削除
multipass delete primary
# multipass delete <仮想環境名>
起動中の環境に対して、delete
コマンド実行した場合は、自動で仮想環境を停止してから削除が実施されます。
復旧
delete
コマンドは完全に環境を削除しないため、下記コマンドから復旧することも可能です。
multipass recover primary
# multipass recover <仮想環境名>
破棄
完全に削除を実施するには、delete
後にpurge
を実施してください。
multipass purge
対象の環境について一発で完全に削除を実施するにはdelete
コマンドに-p
または--purge
オプションを付与して実施してください。[2]
multipass delete primary -p
# multipass delete <仮想環境名> -p
オプションを設定して仮想環境作成
前節では、最もシンプルな方法で仮想環境の作成を実施しました。
本節では、OSイメージやリソース設定などをした上で、仮想環境を作成する方法を紹介します。
利用可能な Ubuntu ベースイメージを確認
前節で デフォルト環境 primary を作成した時は、自動的に 22.04 LTS のイメージを使用していましたが、find
コマンドで使用可能なイメージ一覧を確認できます。
通常のイメージ以外にも、jellyfin
やdocker
、minikube
がすでに導入済みのイメージを選択することも可能です。[3]
multipass find
Image Aliases Version Description
20.04 focal 20240220 Ubuntu 20.04 LTS
22.04 jammy,lts 20240221 Ubuntu 22.04 LTS
23.10 mantic 20240209 Ubuntu 23.10
Blueprint Aliases Version Description
anbox-cloud-appliance latest Anbox Cloud Appliance
charm-dev latest A development and testing environment for charmers
docker 0.4 A Docker environment with Portainer and related tools
jellyfin latest Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media.
minikube latest minikube is local Kubernetes
ros-noetic 0.1 A development and testing environment for ROS Noetic.
ros2-humble 0.1 A development and testing environment for ROS 2 Humble.
リソースの割り当てを設定して仮想環境の立ち上げ
仮想環境へのcpuやメモリ、ディスクのリソース割り当てを設定して仮想環境を作成します。
下記のコマンドでは、CPU コアが2つ、メモリが 2[GByte]、ディスクサイズが 10[GByte] を割り当てた 22.04 イメージをベースとする仮想環境を作成します。
仮想環境名(インスタンス名)は--name
オプションで hoge としており、この名前がホスト名にもなります。
multipass launch --cpus 2 --memory 2G --disk 10G --name hoge 22.04
# multipass launch --cpus <割り当てるCPU数> --memory <割り当てるメモリ数[GByte]>G --disk <割り当てるディスクサイズ>G --name <仮想環境名> <イメージタグ>
作成が完了したら、下記コマンドでshellログインできます。
multipass shell hoge
# multipass shell <仮想環境名>
ローカル環境ディレクトリをマウント
前説のデフォルト環境 primary では、ローカル環境のホームディレクトリが仮想環境上のHome
に紐付けられており、ローカル環境のファイルにアクセスできる状態になっていました。
しかし、launch
コマンドにより独自で作成した環境では特別な設定がされていないため、環境作成とは別途でマウント作業を実施します。
仮想環境上で、マウント先のディレクトリを作成します。ディレクトリは任意の名前で良いですが今回はsync_hoge
という名前にします。
ディレクトリの作成後、sync_hoge
までのフルパスを控えておきます。
ubuntu@hoge:~$ mkdir sync_hoge
ubuntu@hoge:~$ cd sync_hoge
ubuntu@hoge:~/sync_hoge$ pwd
/home/ubuntu/sync_hoge
ubuntu@hoge:~$ exit
仮想環境上で、マウント先のディレクトリを作成後下記のmount
コマンドで、任意のローカル環境のディレクトリをマウントできます。
multipass mount /Users/<user_name>/Desktop/workspace hoge:/home/ubuntu/sync_hoge
# multipass mount <ローカル環境の任意ディレクトリまでのフルパス> <仮想環境名>:<マウント先ディレクトrまでのフルパス>
## windows はローカル環境のパスの区切りを\で表記するように注意
ローカル環境上の現在のディレクトリをマウントしたいのであれば下記が便利です。
multipass mount $(pwd) hoge:/home/ubuntu/sync_hoge
multipass mount (Get-Location).Path hoge:/home/ubuntu/sync_hoge
macOS でマウントに失敗する場合のトラブルシュート
マウント機能を利用するためには、仮想環境から Mac 上のディスク(ディレクトリ)にアクセスを許可する必要がある場合があります。(OSバージョンの問題なのか、フルディスクアクセスの一覧にmultipassd
が表示されないケースもあるようです。)
下記手順の実施してください。
- ディスクトップ画面左上🍎アイコンをクリック
- 「システム設定」をクリック
- 「プライバシーとセキュリティ」の一覧から「フルディスクアクセス」を選択
- 「フルディスクアクセス」の一覧から multipassd を有効化
3. 「プライバシーとセキュリティ」の一覧から「フルディスクアクセス」を選択
4. 「フルディスクアクセス」の一覧から multipassd を有効化
マウントの状況はmultipass info hoge
から確認できます。
multipass info hoge
Name: hoge
State: Running
Snapshots: 0
IPv4: 192.168.64.231
Release: Ubuntu 22.04.4 LTS
Image hash: edba2f9aad6f (Ubuntu 22.04 LTS)
CPU(s): 2
Load: 0.00 0.00 0.00
Disk usage: 1.6GiB out of 9.6GiB
Memory usage: 162.4MiB out of 1.9GiB
Mounts: /Users/<user_name>/Desktop/workspace => /home/ubuntu/sync_hoge
UID map: 501:default
GID map: 20:default
対象環境についてマウントを解除するには下記のコマンドを実施します。
multipass umount hoge
# multipass umount <仮想環境名>
multipass の紹介できなかったコマンドについては公式ドキュメントを参照してください。
Docker インストール
Docker のインストールは公式ぺージの手順を参考に導入をすれば良いのですが、しばしばこの手順が変わるため、コマンドを直接実施する方法ではなく、convenience scriptを利用した方法によるインストールを行います。[4] version
オプションでインストールしたいdocker
のバージョンを指定できます。
Docker バージョンは下記リンク先のリリースタグから確認できます。
ubuntu@hoge:~$ curl -fsSL https://get.docker.com -o install-docker.sh
ubuntu@hoge:~$ bash install-docker.sh --version 26.0 --dry-run
ubuntu@hoge:~$ bash install-docker.sh --version 26.0
sudo
なしでdocker
を実行するために、ubuntu
ユーザーをdocker
グループに追加します。
ubuntu@hoge:~$ sudo groupadd docker
ubuntu@hoge:~$ sudo gpasswd -a $USER docker
ubuntu@hoge:~$ exit
再度仮想環境にログインし、下記コマンドで実行確認ができます。
ubuntu@hoge:~$ docker run hello-world
ssh 接続設定
multipass shell hoge
で仮想環境へのログインはできるようになりましたが、仮想環境のファイル操作をすべて CLI で実施するのは大変なため、GUI を用いる方が作業効率が良いです。
このため、仮想環境上のファイル操作を GUI で行うために VSCode 拡張の Remote-SSH を利用します。
また、特別な設定をしない限り、仮想環境へのパスワード認証による ssh ログインはできないように設定されているため、鍵情報を使った ssh 接続の必要があります。
基本設定
VSCode の Remote-SSH は ~/.ssh/config
を参照して仮想環境への接続を行うためconfig
ファイルに設定を記載しておく必要があります。この際、~/.ssh
下に鍵を配置してconfig
に設定をすべて記述しても良いのですが、仮想環境毎に鍵と設定ファイルを一元的に管理できた方が便利です。[5] このため、仮想環境名のディレクトリを作成し、そのディレクトリ下に設定ファイルと鍵を配置します。~/ssh/config
へはInclude
を利用して設定ファイルを参照するようにします。
# 仮想環境の名前を設定
INSTANCE_NAME="hoge"
# ssh 接続設定用に仮想環境名ディレクトリを切る
WORKSPACE="${HOME}/.ssh/multipass/${INSTANCE_NAME}"
mkdir -p "${WORKSPACE}"
# 仮想環境名の鍵生成
## パスフレーズは空
ssh-keygen -t ecdsa -b 521 -N "" -f "${WORKSPACE}/${INSTANCE_NAME}"
# config ファイル作成
touch "${WORKSPACE}/config"
# 公開鍵を仮想環境の authorized_keys に追加
## 下記コマンドでなくても multipass shell <仮想環境名> でログインして、 authorized_key に直接公開鍵を追加するでも OK
multipass exec hoge --working-directory "/home/ubuntu/.ssh" -- bash -c "echo '$(cat ${WORKSPACE}/${INSTANCE_NAME}.pub)' | tee -a authorized_keys"
# multipass exec <仮想環境名> --working-directory <コマンド実行ディレクトリ> -- <実行コマンド>
# 仮想環境の名前を設定
$INSTANCE_NAME="hoge"
# ssh 接続設定用に仮想環境名ディレクトリを切る
$WORKSPACE="$HOME\.ssh\multipass\$INSTANCE_NAME"
New-Item -ItemType Directory -Force -Path "$WORKSPACE"
# 仮想環境名の鍵生成
## パスフレーズは空
ssh-keygen -t ecdsa -b 521 -N "" -f "$WORKSPACE\$INSTANCE_NAME"
# config ファイル作成
New-Item -ItemType File -Path "$WORKSPACE\config"
# 公開鍵を仮想環境の authorized_keys に追加
## 下記コマンドでなくても multipass shell <仮想環境名> でログインして、 authorized_key に直接公開鍵を追加するでも OK
multipass exec hoge --working-directory "/home/ubuntu/.ssh" -- bash -c "echo '$(Get-Content $WORKSPACE\$INSTANCE_NAME.pub)' | tee -a authorized_keys"
~/.ssh/multipass/hoge/config
および~/.ssh/config
ファイルについて適当なテキストエディタで下記の設定を追加して下さい。
Host hoge
HostName <仮想環境のIPアドレス>
User ubuntu
IdentityFile ~/.ssh/multipass/hoge/hoge
IdentitiesOnly yes
ServerAliveInterval 60
Include ~/.ssh/multipass/hoge/config
HostName の<仮想環境のIPアドレス>部分はmultipass info hoge
でIPv4:
のアドレスを記載して下さい。
ssh ログインで仮想環境に入れることが確認できたら、ssh 接続の設定は完了です。
ssh hoge
The authenticity of host '192.168.64.231 (192.168.64.231)' can't be established.
ED25519 key fingerprint is SHA256:Vt7KevcPFvk4QzGXMge+Fmae16nLmjGk5U40iWYlBYQ.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.64.231' (ED25519) to the list of known hosts.
Avahi を使って仮想環境の接続先を固定化
Multipass は、仮想環境を立てるたびに、IP アドレスが自動で割り当てられるため、同じホスト名のインスタンスを再度立て直した時に、仮想環境の ssh 接続設定のHostName
を編集し直す必要があります。特に、Windows 環境では PC の再起動のたびに IP アドレスが変わってしまいます。
Multipass の公式ドキュメントでは、IPの固定化をするためにブリッジを手動で作成する方法が紹介されていますが、手順が各々のホスト環境依存になってしまう点が気に入りません。
これらの問題を解決してくれるのが、Avahi です。
仮想環境上でavahi-deamon
を動かしておくだけで、<仮想環境のホスト名>.local
の形式でローカル環境におけるホスト名を解決してくれます。[6]
avahi-deamon
のインストール方法は下記で実施します。
systemctl status
でステータスがactive
になっていれば、デーモンが起動しています。
ubuntu@hoge:~$ sudo apt-get update
ubuntu@hoge:~$ sudo apt-get install avahi-daemon
ubuntu@hoge:~$ sudo systemctl status avahi-daemon
Avahi
が有効化されたので、HostName
を修正します。
Host hoge
- HostName <仮想環境のIPアドレス>
+ HostName hoge.local
User ubuntu
IdentityFile ~/.ssh/multipass/hoge/hoge
IdentitiesOnly yes
ServerAliveInterval 60
以上で、接続先を擬似的に固定化できました。
VSCode Remote-SSH で接続
ssh 接続設定が完了したので、Remote-SSH を利用して仮想環境への接続を行います。
以降は VSCode 上の操作となり、Remote-SSH がすでに導入されていることを前提とします。
もし、導入がまだの方は VSCode の Extensions タブから検索してインストールを実施して下さい。
-
緑の矢印の先のアイコン
><
をクリック
Remote-SSH を起動 -
コマンドパレットで、仮想環境のホスト名を選択して、仮想環境に接続します。
接続先の選択 -
「Open Folder」ボタンから VSCode で開きたい仮想環境上のディレクトリ名を指定します。
仮想環境にアタッチされた VSCode
以上で、作成した仮想環境に Remote-SSH でアクセスできました。
ポートフォワーディング
仮想環境上で立ち上げた Web サーバーにローカル環境のブラウザからアクセスするためには、仮想環境上のポートにローカル環境のポートで繋ぐ、ポートフォワーディングを行う必要があります。
ターミナルから ssh 接続する場合
ssh 接続時にポートフォワーディングするためには、下記のように ssh 接続の設定ファイルを書き換えます。
Host hoge
HostName hoge.local
User ubuntu
IdentityFile ~/.ssh/multipass/hoge/hoge
IdentitiesOnly yes
ServerAliveInterval 60
+ LocalForward 8080 127.0.0.1:8080
この設定は、LocalForward 直後の8080
が仮想環境の Web サーバーが使用する予定のポートであり、そのポートをクライアントであるローカル環境127.0.0.1
の8080
ポートへ繋ぎ込むことを表します。
設定が完了したら、仮想環境に ssh ログインします。ssh 接続中はポートフォワーディングが有効になります。
ssh hoge
仮想環境の Ubuntu 22.04 にはデフォルトで python 3.10.12 が導入されていますので、こちらを利用して接続テスト用の Webサーバーを立ち上げます。Web サーバーのポートは設定ファイルと同じ8080
にします。
ubuntu@hoge:~$ python3 --version
Python 3.10.12
ubuntu@hoge:~$ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
ページを確認するためローカル環境で、Chrome などのブラウザを立ち上げて検索バーに127.0.0.1:8080
またはlocalhost:8080
と入力します。
下記のように仮想環境のホームディレクトリの一覧が表示されていれば正しく接続できています。
ポートフォワーディングによる仮想環境の Web サーバーへの接続テスト
ssh 接続を終了すると、ポートフォワーディングが解除されるため、アクセスできなくなります。
VSCode Remote-SSH を使う場合
VSCode Remote-SSH で接続の手順から、仮想環境へ接続を行い。python から 接続テスト用の Web サーバーを下記のように起動します。
ubuntu@hoge:~$ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
VSCode では、ポート指定のアプリケーションを起動すると、自動的にローカル環境へポートの繋ぎこみをやってくれます。ローカル環境のどのポートに繋ぎ込まれたかは、VSCode の画面の Ports(差し込みプラグのアイコン) のタブから確認できます。
ssh 接続設定で LocalForward を設定していない場合
また、すでにローカル環境側で使用しているポート、または ssh 接続設定で、常にバインドされるポートが指定されている)がある場合には、利用されていないポート(今回であれば8081
)を VSCode が自動で指定してくれます。今回のケースでは、localhost:8080
またはlocalhost:8081
で ページにアクセスできます。
ssh 接続設定で LocalForward 8080 127.0.0.1:8080 で設定されていた場合
ポートの欄をクリックすると、下記のように Forwarded Address のページをすぐ確認するための便利なボタンが配置されています。とても便利なので活用しましょう。
Forwarded Ad...の 左: クリップボードへコピー、中央: ブラウザ起動、右: VSCode 内で対象ページ起動
以上で仮想環境上の Web サーバーへアクセスするためのポートフォワーディングの設定について紹介しました。
Cloud-init による環境設定の自動化
ここまでで、Vscode Remote-SSH 可能な Docker 環境を構築できることは分かりましたが、新しく環境を作成する毎に Docker
や Avahi
のインストール、公開鍵の追加作業を実施するのは大変です。
Multipass では Cloud-init という yaml 形式の複数 Linux ディストリビューションに対応したクロスプラットフォームなインスタンスの初期化方法を利用することができます。これにより下記のような作業を環境初期化時に実施可能です。
- 仮想環境のホスト名の設定
- ロケールの設定
- タイムゾーンの設定
- ssh 接続におけるパスワード認証の禁止
- パッケージのアップデート & アップグレード
- snap パッケージのインストール
- ユーザーの作成
- ファイルの作成 & 追記
- コマンドの実施
下記に Multipass の仮想環境作成で有用と思われる Cloud-init のテンプレートを示します。
前提としてマウント先のsync_hoge
ディレクトリには任意の Monorepository がマウントされることを想定しています。つまり、 Polyrepo のために複数のマウントポイント(マウント先ディレクトリ)を事前に用意していません。
hoge 環境の hoge ユーザーで作成する場合であれば、<YOUR SSH PUBLIC KEY>
部分を~/.ssh/multipass/hoge/hoge.pub
の公開鍵の内容で書き換えるだけで hoge.yml
は動作します。
#cloud-config
hostname: hoge # この仮想環境のホスト名を "hoge" に設定
locale: en_US.UTF-8 # システムロケールを英語(us)に設定
timezone: Asia/Tokyo # システム時刻を日本時間に設定 UTC+9:00
ssh_pwauth: no # パスワード認証による ssh ログインを禁止
package_update: true # パッケージインストール前にパッケージリポジトリを更新
package_upgrade: true # パッケージインストール前に既存パッケージを更新
package_reboot_if_required: true # 再起動が必要なパッケージがある場合に再起動を実施
# apt パッケージをインストール
packages:
- sshfs # ssh 接続でディレクトリマウントするためのパッケージ
- curl # http リクエスト飛ばせる定番コマンド
- ca-certificates # 基本的なCA認証を取得するパッケージ
- vim # Let me out !!! のミームでお馴染みの CLI テキストエディタ
- nano # vim が苦手な人向けのシンプルなテキストエディタ
- jq # json ファイルのパーサー
- tree # ディレクトリやファイルをツリー表示するコマンド
- git # ソースコードのバージョン管理
- zstd # zstandard 形式の圧縮コマンド
- avahi-daemon # ローカル環境のホスト名解決
# snap パッケージのインストール
snap:
commands:
- snap install yq --classic # yaml ファイルのパーサー
# ユーザー作成
users:
- name: hoge # 新規作成するユーザー名の設定
lock_passwd: true # パスワードによるログインを禁止
sudo: ALL=(ALL) NOPASSWD:ALL # sudo 実行の際にパスワード入力を不要化
shell: /bin/bash # デフォルトで使用する shell を設定
ssh-authorized-keys: # ssh 接続時に使用する、公開鍵を設定
- <YOUR SSH PUBLIC KEY> # ~/.ssh/multipass/hoge/hoge.pub を記載
groups: # docker コマンド実施の際に sudo を不要にするため docker グループへ追加
- docker
# ユーザーのパスワード設定
chpasswd:
list: | # ユーザー "hoge" にパスワードを "huga" を設定
hoge:huga
expire: false # パスワードに期限を設定しない
# ファイルの作成 & 追記
write_files:
# マウント先 の git リポジトリが安全であることを追加
- path: /home/hoge/.gitconfig # ファイルのパス
owner: hoge:hoge # ファイルの権限設定 ユーザー:グループ
append: true # 追記可能
defer: true # ユーザー作成が終わるまでこのファイル作成を遅延
content: | # ファイル内容
[safe]
directory = /home/hoge/sync_hoge
# インタラクティブモードで bash を開いた際の処理を追加
- path: /home/hoge/.bashrc
owner: hoge:hoge
append: true
defer: true
content: |
# マウントディレクトリの環境変数を設定
readonly SYNC_DIR=/home/hoge/sync_hoge
# docker compose のエイリアスを設定(SYNC_DIR下に compose.yml があることを想定)
alias cdsync='cd ${SYNC_DIR}'
alias dcu='pushd ${SYNC_DIR}; docker compose up -d; popd'
alias dcd='pushd ${SYNC_DIR}; docker compose down; popd'
alias dcs='pushd ${SYNC_DIR}; docker compose stop; popd'
alias dcr='pushd ${SYNC_DIR}; docker compose restart; popd'
alias dcrmia='pushd ${SYNC_DIR}; docker compose down --rmi all --volumes --remove-orphans; popd'
# Remote-SSH ログイン時に vscode 拡張を自動インストール
if [[ -e "$(which code)" ]] && [[ -d "/home/hoge/.enable_install_vscode_extensions" ]]; then
xargs -I {} code --install-extension {} --force < /home/hoge/vscode_extensions.txt
rm -rf /home/hoge/.enable_install_vscode_extensions
fi
[[ "${TERM_PROGRAM}" != "vscode" ]] && rm -rf /home/hoge/.enable_install_vscode_extensions
# ssh ログイン時の処理を追加
- path: /home/hoge/.profile
owner: hoge:hoge
append: true
defer: true
content: | # vscode 拡張のインストールを有効化するディレクトリを作成
mkdir -p /home/hoge/.enable_install_vscode_extensions
# 自動インストールする vscode 拡張の ID 一覧
- path: /home/hoge/vscode_extensions.txt
owner: hoge:hoge
defer: true
content: |
mosapride.zenkaku
ms-azuretools.vscode-docker
oderwat.indent-rainbow
shardulm94.trailing-spaces
streetsidesoftware.code-spell-checker
# コマンド実行(すべての初期化処理の最後に実行)
runcmd:
# マウント先のディレクトリを "hoge" ユーザーの権限で作成
- su -c "mkdir /home/hoge/sync_hoge" - hoge
# docker インストール
- curl --proto '=https' --tlsv1.2 -sSfL https://get.docker.com | bash -s -- --version 26.0
# act インストール
- curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/nektos/act/master/install.sh | bash -s -- -b /usr/local/bin v0.2.60
この Cloud-init のテンプレートは、メタ文字列hoge
やhuga
を任意の文字列に適宜置換頂き、apt や snap パッケージおよび VSCode の拡張を各自お好みで削除・追加してご利用ください。
Cloud-init の詳細は公式ドキュメントを参照して下さい。
Cloud-init を利用した、仮想環境の作成は下記コマンドで実施します。
# 既存の hoge 環境が残っている場合は削除してから作成を実施して下さい
# multipass delete hoge -p
multipass launch --cpus 2 --disk 16G --memory 2G --cloud-init hoge.yml --name hoge --timeout 1800 22.04
また、ユーザー作成でユーザー名をhoge
に指定した場合は、ssh 接続のログインユーザーを変更して下さい。
Host hoge
HostName hoge.local
- User ubuntu
+ User hoge
IdentityFile ~/.ssh/multipass/hoge/hoge
IdentitiesOnly yes
ServerAliveInterval 60
以上で Cloud-init による環境設定の自動化を行い、仮想環境の作成ができました。
Cloud-init では自動化できないこと
Multipass は Cloud-init を使用することで、環境作成に必要な多くの作業を自動化を達成しましたが、例えば下記の作業が手作業として残ってしまっています。
- ssh 接続のための鍵の作成および設定ファイルの作成
- 公開鍵の Cloud-init ファイルへの記載
- 作成ユーザー名に応じた、Cloud-init ファイルの各種パスの変更
- Docker や act の動的なインストールバージョン変更
- ディレクトリマウント
- (VSCodeを使わないケースは必須)ssh 設定へ LocalForward の設定追加・変更
このような Cloud-init でカバーできない作業(特に、Cloud-init 自身の内容変更)の自動化については、shell スクリプトなどを活用して自動化するべきですが、より進んだ内容になるため別の記事としてご紹介できればと思います。
おわりに
本記事では、Multipass を利用して Ubuntu の仮想環境上に Docker 環境を構築する方法について紹介しました。
Multipass については、導入から基本的な使い方・Dockerの導入・作業の自動化までとかなり網羅的に解説しました。また、Multipass を Docker ホスト環境としてより便利に活用していくためのトピックとして、Include 句を使った ssh 設定・VSCode Remote-SSH・Avahi によるアドレスの固定化、ポートフォワーディングについて紹介しました。
かなり内容の多い記事になってしまいましたが、皆様がより良いローカル仮想環境構築する際の一資料としてご活用頂けますと幸いです。
謝辞
本記事について、公開前にレビュー・アドバイスしてくれた3名の友人に感謝!
- takanari
- lenhaba
- akimotty
-
Dockerは Linux のカーネルを使用して動いているので、Linux 環境上に導入してしまうのが都合が良いためです。 ↩︎
-
個人的には、後述する Cloud-init を利用して仮想環境作成の自動化ができていれば、環境の再作成は容易に可能なため、
docker compose down
ぐらいの気持ちで、delete -p
を使用しても問題ないと思います。ただし、誤削除には気をつけましょう。 ↩︎ -
このような便利なイメージを利用することも可能ですが、OSバージョンを指定できない問題があります。個人的には、OSバージョンのイメージを選択して、Cloud-init に使用したいツールのインストール手順を記載しておくのが良い方法だと考えます。この方法は「Cloud-init を使った自動化」の章で紹介します。 ↩︎
-
公式ページにも記載がありますが、convenience script によるインストールは本番環境では使用してはいけません。 ↩︎
-
~/.ssh/config
に設定を直接書かずにInclude
で参照することによって、対象の環境のInclude
の行を記載するか・削除するかだけで設定の ON/OFF ができるようになるので非常に便利です。仮想環境は他のサーバーへの接続設定と違ってライフサイクルが短く、頻繁に ssh の設定・削除が必要になるのでので、Include
を使うと作業が捗ります。 ↩︎ -
仮想環境のホスト名は
multipass launch
コマンドの--name
オプションで与えた名前がホスト名になります。後述する Cloud-init を使えば自由にホスト名を設定可能です。 ↩︎
Discussion