mrsk gem README: 37signalsの多機能コンテナデプロイツール(翻訳)
MRSKは、Dockerを利用してWebアプリケーションをベアメタルからクラウドVMまでダウンタイムゼロでデプロイできます。新しいアプリケーションコンテナが起動してから古いコンテナが停止されるまでの間、動的リバースプロキシであるTraefikを利用してリクエストを保持します。複数のホストに対してシームレスに動作し、SSHKitを利用してコマンドを実行します。当初Railsアプリケーション向けに構築されましたが、Dockerでコンテナ化可能なあらゆる種類のWebアプリケーションで動作します。
以下のScreencastもどうぞ。Discordにもぜひご参加ください。
インストール方法
Rubyが使える環境であれば、以下を実行してMRSKをグローバルにインストールできます。
gem install mrsk
または、Docker化バージョンのMRSKをエイリアス経由で実行することも可能です(以下を自分の${SHELL}rc
ファイルに追加しておくと再利用がシンプルになります)。
alias mrsk='docker run --rm -it -v $HOME/.ssh:/root/.ssh -v /var/run/docker.sock:/var/run/docker.sock -v ${PWD}/:/workdir ghcr.io/mrsked/mrsk'
次に、アプリケーションディレクトリでmrsk init
を実行します(Railsアプリでbin/mrsk binstub
を使いたい場合はmrsk init --bundle
を実行します)。
終わったら新しいconfig/deploy.yml
ファイルを編集します。このファイルは以下のようにシンプルです。
service: hey
image: 37s/hey
servers:
- 192.168.0.1
- 192.168.0.2
registry:
username: registry-user-name
password:
- MRSK_REGISTRY_PASSWORD
env:
secret:
- RAILS_MASTER_KEY
次に.env
ファイルを編集して、自分が使うレジストリのパスワードをMRSK_REGISTRY_PASSWORD
環境変数に追加します(Railsアプリをproduction環境で動かすためにRAILS_MASTER_KEY
も追加します)。
以上で、サーバーにデプロイする準備が整います。
mrsk deploy
これにより、以下が行われます。
- SSH経由でサーバーに接続する(デフォルトではrootを利用し、sshキーで認証される)
- DockerがなさそうなサーバーではDockerをインストールする(apt-getを利用): これを行うにはssh経由でのrootアクセスが必要です
- レジストリにローカルとリモートの両方でログインする
- アプリケーションのルートディレクトリにある標準のDockerfileでイメージをビルドする
- イメージをレジストリにpushする
- レジストリにあるイメージをサーバーにpullする
- Traefikが実行中で、トラフィックをポート80で受信することを確認する
- アプリが
GET /up
に200 OK
を返すことを確認する - 現在のgitバージョンハッシュと一致するアプリのバージョンで、新しいコンテナを起動する
- 以前のバージョンで実行されていた古いコンテナを停止する
- 未使用のイメージを削除してコンテナを停止し、サーバーがあふれないようにする
できました!これで、すべてのサーバーがポート80でアプリを配信するようになります。実行するサーバーが1個だけの場合は、これでOKです。実行するサーバーが複数の場合は、ロードバランサーをサーバーの手前に配置する必要があります。
ビジョン
Webアプリを手軽にデプロイする商用サービスは、この何十年の間に爆発的に増加しています。その先駆けとなったHerokuの素晴らしさは、永遠に競合他社の先を行くかと思われるほどでした。近年はFly.ioやRenderなどの優れた競合サービスも登場していますし、ホスト型KubernetesによってAWSやGCPやDigital Oceanなどあらゆる場所での作業が楽になりつつあります。しかしこれらはすべて、クラウド上のコンピュータを有料でレンタルする形になります。自社内にあるハードウェア上で実行したい場合は、たとえ将来の移行パスが明確であったとしても、そうした商用プラットフォームにどの程度ロックインされるかを慎重に見極める必要があります。できれば、ビジネスが請求書の山に飲み込まれる前に!
MRSKは、これら商用サービスが切り開いてきた先進的なエルゴノミクスを取り入れて、Webサービスをあらゆる場所にデプロイ可能にすることを目指しています。デプロイ先がマネージドサービスなし・価格上乗せなしの低価格サービス(Digital Ocean、Hetzner、OVHなど)であろうと、自社内に設置されているベアメタルマシンであろうと、まったく変わりません。SSHキーを追加した以外に何も準備していない素のUbuntuサーバーのIPアドレスリストを設定ファイルに記入すれば、文字通り数分で実行できるようになるのです。
この手法によって移植性が大幅に高まります。Webアプリを複数のクラウドにデプロイするのも同じように手軽にできます。普段は独自ハードウェアで運用し、アクセスが集中する時期が近づいたらクラウドにデプロイして可用性を高めることも可能です。ツール周りが単一プロバイダにロックインされていなければ、多くの魅力的なオプションが利用できます。
MRSKが最終的に目指すのは、商用サービスに縛られていないオープンソースのツールを用いて、本番運用までの複雑さを軽減することです(ゼロではありません、念のため)。LinuxやDockerの基本的な操作がまだ難しいのであれば、これまでどおりフルマネージドサービスに乗る方がおそらくよいでしょう。しかしそうした概念に慣れてくれば、MRSKを使う準備はすぐにでも整います。
Capistrano/Kubernetes/Docker Swarmでいいのでは?
MRSKは基本的に「コンテナ用Capistrano」です。事前にサーバーを注意深くセットアップする必要もありませんし、サーバーで適切なバージョンのRubyやその他の依存関係を事前に準備しておく必要もありません。必要なものはすべてDockerイメージの中で動きます。真新しいUbuntuサーバー(でも何でも)を起動してMRSKのサーバーリストに追加すれば、Dockerで自動プロビジョニングされて即座に実行されます。Dockerレイヤキャッシュ機能によってデプロイも高速化され、サーバーに煩わされることも減ります。さらに、MRSKでビルドしたイメージは、後でCIや内部調査にも転用できます。
Kubernetesは猛獣です。独自ハードウェア上での運用は気の小さい人には向いていません。他の誰かのプラットフォーム上で動かすのであれば(Renderがやっているような透過的運用か、AWSやGCP上で明示的に運用するか)、Kubernetesは良いオプションですが、クラウドと独自ハードウェアの間を自由に移動したり両者を混在させたりするなら、MRSKの方がずっとシンプルです。MRSKでは基本的なDockerコマンドが呼び出されているだけです。
Docker SwarmはKubernetesよりずっとシンプルですが、それでもステートのreconciliation(調整)を利用する宣言的モデル上に構築される点は同じです。MRSKはあえてCapistranoと同様の命令的コマンド中心の設計を採用しています。
最終的にWebアプリのデプロイ方法はいくらでも存在しますが、MRSKは、私たち37signalsが現代のコンテナ化ツールのメリットを失わずにHEYをクラウドから自社に取り戻すのに使っているツールキットなのです。
MRSKをDockerから実行する
MRSKは、rails/dockedと同様にDockerコンテナでパッケージ化されています。これにより、Docker以外の依存関係をインストールせずに、(アプリケーションのディレクトリから)MRSKを実行可能になります。
コンテナ作業をさらに便利にするために、以下のエイリアスをbashのプロファイル設定に追加してください。
alias mrsk="docker run -it --rm -v '${PWD}:/workdir' -v '${SSH_AUTH_SOCK}:/ssh-agent' -v /var/run/docker.sock:/var/run/docker.sock -e 'SSH_AUTH_SOCK=/ssh-agent' ghcr.io/mrsked/mrsk:latest"
MRSKはリモート接続をsshで確立するので、sshエージェントにアクセス可能になっている必要があります。上のコマンドは、ボリュームマウントを用いてコンテナ内でボリュームを利用可能にし、コンテナ内部のsshエージェントがそれを利用できるように設定します。
設定
必要な環境変数を.envファイルで読み込む
MRSKはdotenvを用いて、アプリケーションのルートディレクトリに置かれている.envファイルの環境変数を自動的に読み込みます。この.envファイルは、MRSK_REGISTRY_PASSWORD
やデータベースパスワードなどの変数を設定するのに利用できます。ただし、この理由によって、.envファイルは決してGitにチェックインしたりDockerfileに取り込んだりしてはいけません。形式は以下のようなキーバリューになります。
MRSK_REGISTRY_PASSWORD=pw
DB_PASSWORD=secret123
生成された.envファイルを利用する
1Passwordを秘密情報ストアとして利用する
秘密情報ストアを1Passwordなどに集約している場合は、秘密情報を取得する.env.erb
テンプレートを作成できます。以下は.env.erb
ファイルの例です。
<% if (session_token = `op signin --account my-one-password-account --raw`.strip) != "" %># Generated by mrsk envify
GITHUB_TOKEN=<%= `gh config get -h github.com oauth_token`.strip %>
MRSK_REGISTRY_PASSWORD=<%= `op read "op://Vault/Docker Hub/password" -n --session #{session_token}` %>
RAILS_MASTER_KEY=<%= `op read "op://Vault/My App/RAILS_MASTER_SECRET" -n --session #{session_token}` %>
MYSQL_ROOT_PASSWORD=<%= `op read "op://Vault/My App/MYSQL_ROOT_PASSWORD" -n --session #{session_token}` %>
<% else raise ArgumentError, "Session token missing" end %>
このテンプレートファイルはGitにチェックインしても安全です。アプリをデプロイできるユーザーなら誰でもmrsk envify
を実行して、アプリを最初にセットアップしたり、パスワードを変更して正しい.env
ファイルを取得したりできます。
デプロイ先ごとに環境変数を使い分ける必要がある場合は、.env.destination.erb
テンプレートで設定できます。mrsk envify -d staging
を実行すると.env.staging
ファイルが生成されます。
Bitwardenを秘密情報ストアとして利用する
Bitwardenなどのオープンソースの秘密情報ストアを使う場合は、以下のような.env.erb
テンプレートで秘密情報を探索できます。
SOME_SECRET
はbitwardenの保管庫(vault)の秘密メモに保存できます。
$ bw list items --search SOME_SECRET | jq
? Master password: [hidden]
[
{
"object": "item",
"id": "123123123-1232-4224-222f-234234234234",
"organizationId": null,
"folderId": null,
"type": 2,
"reprompt": 0,
"name": "SOME_SECRET",
"notes": "yyy",
"favorite": false,
"secureNote": {
"type": 0
},
"collectionIds": [],
"revisionDate": "2023-02-28T23:54:47.868Z",
"creationDate": "2022-11-07T03:16:05.828Z",
"deletedDate": null
}
]
上のjson
から SOME_SECRET
のid
を抽出して、以下の.erb
で利用します。
.env.erb
サンプルファイル:
<% if (session_token=`bw unlock --raw`.strip) != "" %># Generated by mrsk envify
SOME_SECRET=<%= `bw get notes 123123123-1232-4224-222f-234234234234 --session #{session_token}` %>
<% else raise ArgumentError, "session_token token missing" end %>
これで、アプリをデプロイできるユーザーなら誰でもmrsk envify
を実行して.env
を生成できます。
Docker Hub以外のレジストリを使用する
デフォルトのレジストリはDocker Hubですが、registry/server
で変更可能です。
registry:
server: registry.digitalocean.com
username:
- DOCKER_REGISTRY_TOKEN
password:
- DOCKER_REGISTRY_TOKEN
秘密情報DOCKER_REGISTRY_TOKEN
への参照は、MRSKを実行中のマシン上のENV["DOCKER_REGISTRY_TOKEN"]
を探索します。
root以外のSSHユーザーを使う
デフォルトのSSHユーザーはrootですが、ssh/user
で変更可能です。
ssh:
user: app
SSHプロキシホストを使う
プロキシホスト経由で接続する必要がある場合は、ssh/proxy
で指定できます。
ssh:
proxy: "192.168.0.1" # デフォルトユーザーはroot
ユーザーも指定できます。
ssh:
proxy: "app@192.168.0.1"
環境変数を使う
以下を使うと、アプリのコンテナにenv
の環境変数を注入できます。
env:
DATABASE_URL: mysql2://db1/hey_production/
REDIS_URL: redis://redis1:6379/1
機密の環境変数を使う
機密にしておくべき環境変数がある場合は、env
ファイルでclear
ブロックとsecret
ブロックを使い分けることが可能です。
env:
clear:
DATABASE_URL: mysql2://db1/hey_production/
REDIS_URL: redis://redis1:6379/1
secret:
- DATABASE_PASSWORD
- REDIS_PASSWORD
secret
ブロックの環境変数リストは、実行時にローカル環境から展開されます。つまり、DATABASE_PASSWORD
の秘密情報への参照は、MRSKを実行している環境でENV["DATABASE_PASSWORD"]
を探索します。これは、ビルド用の秘密情報の場合と同じ要領です。
参照されたsecret
の環境変数が見つからない場合は、KeyError
例外で設定を中止します。
注: secret
の環境変数は、MRSKの出力では値が伏せ字(redacts)になります。clear
の環境変数は、実行時に平文でコンテナに注入されます。
ボリュームを使う
volumes
でカスタムボリュームをアプリのコンテナに追加できます。
volumes:
- "/local/path:/container/path"
MRSKの環境変数
コンテナを実行すると、以下の環境変数が設定されます。
MRSK_CONTAINER_NAME
: ここには現在のコンテナ名とバージョンが含まれます
さまざまな役割のサーバーを使い分ける
デフォルトのWeb以外に、ジョブ実行など別のロール用に別ホストを使う場合は、新しいエンドポイントコマンドでこれらのホストを以下のように指定できます。
servers:
web:
- 192.168.0.1
- 192.168.0.2
job:
hosts:
- 192.168.0.3
- 192.168.0.4
cmd: bin/jobs
注: Traefikは、デフォルトではweb
ロールにのみ(ロールが指定されていない場合すべてのサーバーに)インストールおよび実行されます。Traefikをweb
以外のロールでホストする必要がある場合は、traefik: true
を追加します。
servers:
web:
- 192.168.0.1
- 192.168.0.2
web2:
traefik: true
hosts:
- 192.168.0.3
- 192.168.0.4
コンテナにラベルを付ける
起動されるコンテナにラベルを設定することで、デフォルトのTraefikルールをカスタマイズできます。
labels:
traefik.http.routers.hey.rule: Host(`app.hey.com`)
注意: バッククオートは、ルールを正しく渡し、bashでコマンド置換として扱われないようにするために必要です。
これにより、同じTraefikインスタンスとポートを共有する同一サーバーで複数のアプリケーションを実行できるようになります。利用可能なルーティングルールの完全なリストは https://doc.traefik.io/traefik/routing/routers/#ruleにあります。
ラベルはロールごとにも適用可能です。
servers:
web:
- 192.168.0.1
- 192.168.0.2
job:
hosts:
- 192.168.0.3
- 192.168.0.4
cmd: bin/jobs
labels:
my-label: "50"
コンテナオプションを利用する
コンテナの起動に使うオプションは、options
定義で特殊化できます。
servers:
web:
- 192.168.0.1
- 192.168.0.2
job:
hosts:
- 192.168.0.3
- 192.168.0.4
cmd: bin/jobs
options:
cap-add: true
cpu-count: 4
これで、jon
コンテナがdocker run ... --cap-add --cpu-count 4 ...
で起動します。
ログを設定する
Dockerに渡すログ出力ドライバやオプションは、logging
で設定できます。
logging:
driver: awslogs
options:
awslogs-region: "eu-central-2"
awslogs-group: "my-app"
何も設定しない場合は、すべてのコンテナでデフォルトオプションmax-size=10m
が使われます。Dockerのデフォルトのログ出力ドライバはjson-file
です。
stop_wait_time
を変更する
新規デプロイ時には、実行中の古い各コンテナはSIGTERM
で”graceful”にシャットダウンされ、10
秒の猶予期間を経てからSIGKILL
を送信します。
この値はstop_wait_time
オプションで設定できます。
stop_wait_time: 30
ネイティブのマルチアーキテクチャ向けのリモートビルダーを使う
開発をARM64(Apple Siliconなど)で行っているがAMD64(x86 64ビット)にデプロイしたい場合は、マルチアーキテクチャのイメージを利用できます。デフォルトのMRSKは、QEMUエミュレーション経由でビルドを行うローカルbuildx設定をセットアップします。ただし、特に最初のビルドはかなり遅くなる可能性があります。
ビルダーのオプションを使えば、ローカルではイメージのAMD64部分をネイティブリリースし、リモートではAMD64ホストを利用してイメージのAMD64部分をネイティブビルドする形で高速化できるようになります。
builder:
local:
arch: arm64
host: unix:///Users/<%= `whoami`.strip %>/.docker/run/docker.sock
remote:
arch: amd64
host: ssh://root@192.168.0.1
注意: これを行うには、ビルダーとして使われるリモートホストでDockerが動作していなければなりません。このインスタンスの共有範囲は、同一のレジストリとcredentialを用いるビルドに限定すべきです。
単一アーキテクチャ向けのリモートビルダーを利用する
開発をARM64(Apple Siliconなど)で行っていてAMD64(x86 64ビット)にデプロイしたいが、ローカルで(または他のARM64ホストで)イメージを実行する必要がない場合は、AMD64のみを対象とするリモートビルダーを構成できます。ローカルでのビルドが不要なので、マルチアーキテクチャのビルドよりも少し速くなります。
builder:
remote:
arch: amd64
host: ssh://root@192.168.0.1
マルチアーキテクチャが不要な場合にネイティブビルダーを使う
デプロイしているアーキテクチャと同一のアーキテクチャで開発している場合は、マルチアーキテクチャとリモートビルドの両方をやめることでビルドを高速化できます。
builder:
multiarch: false
これは、デプロイ先サーバーとアーキテクチャを共有しているCIサーバーでMRSKを実行している場合にも適しています。
ビルド時に別のDockerfileやコンテキストを使う
ビルドコマンドに別のDockerfileやコンテキストを渡す必要がある場合は(例: monorepoを使っている場合や別のDockerfileがある場合)、以下のようにbuilder
オプションで変更可能です。
# 別のDockerfileを使う
builder:
dockerfile: Dockerfile.xyz
# コンテキストを設定する
builder:
context: ".."
# Dockerfileとコンテキストを両方指定する
builder:
dockerfile: "../Dockerfile.xyz"
context: ".."
新しいイメージでビルド用秘密情報を使う
イメージによっては、ビルド時に秘密情報を渡す必要が生じることがあります(private gemリポジトリにアクセスするGITHUB_TOKEN
など)。これは、環境変数に秘密情報を設定してビルダーのコンフィグで参照することで可能になります。
builder:
secrets:
- GITHUB_TOKEN
このビルド用秘密情報はDockerfileで参照できます。
# Gemfilesをコピーする
COPY Gemfile Gemfile.lock ./
# 依存関係をインストールする
# (アクセストークン経由でアクセスするprivateリポジトリなど)
# (終了後、GITHUB_TOKENを含むバンドルキャッシュは削除する)
RUN --mount=type=secret,id=GITHUB_TOKEN \
BUNDLE_GITHUB__COM=x-access-token:$(cat /run/secrets/GITHUB_TOKEN) \
bundle install && \
rm -rf /usr/local/bundle/cache
Traefikのコマンド引数を使う
以下のようにtraefikコマンドをカスタマイズできます。
traefik:
args:
accesslog: true
accesslog.format: json
これで、traefikコンテナが--accesslog=true accesslog.format=json
で起動します。
Traefikのホスト-ポートバインディング
デフォルトのTraefikは、ホストマシンのポート80
にバインドします。これは以下のように別のポートを設定可能です。
traefik:
host_port: 8080
traefik向けのDockerオプションを設定する
traefikには以下の方法でDockerオプションを追加で渡せます。
traefik:
options:
publish:
- 8080:8080
volumes:
- /tmp/example.json:/tmp/example.json
memory: 512m
これで、docker run ... --volume /tmp/example.json:/tmp/example.json --publish 8080:8080
のようなコマンドでtraefikコンテナが起動します。
traefikに別のエンドポイントを設定する
traefikには、以下のように複数のエンドポイントを設定できます。
service: myservice
labels:
traefik.tcp.routers.other.rule: 'HostSNI(`*`)'
traefik.tcp.routers.other.entrypoints: otherentrypoint
traefik.tcp.services.other.loadbalancer.server.port: 9000
traefik.http.routers.myservice.entrypoints: web
traefik.http.services.myservice.loadbalancer.server.port: 8080
traefik:
options:
publish:
- 9000:9000
args:
entrypoints.web.address: ':80'
entrypoints.otherentrypoint.address: ':9000'
新規イメージのビルド引数を設定する
秘密情報以外のビルド引数も設定可能です。
builder:
args:
RUBY_VERSION: 3.2.0
このビルド引数はDockerfileで参照可能です。
ARG RUBY_VERSION
FROM ruby:$RUBY_VERSION-slim as base
DB/キャッシュ/検索サービスを使う
アクセサリサービス(追加サービス)もMRSK経由で管理できます。アクセサリとは、アプリが依存する長時間実行サービスのことです。アクセサリサービスはデプロイ時には自動的に更新されません。
accessories:
mysql:
image: mysql:5.7
host: 1.1.1.3
port: 3306
env:
clear:
MYSQL_ROOT_HOST: '%'
secret:
- MYSQL_ROOT_PASSWORD
volumes:
- /var/lib/mysql:/var/lib/mysql
options:
cpus: 4
memory: "2GB"
redis:
image: redis:latest
role:
- web
port: "36379:6379"
volumes:
- /var/lib/redis:/data
internal-example:
image: registry.digitalocean.com/user/otherservice:latest
host: 1.1.1.5
port: 44444
アクセサリーサービスが実行されるホストは、ホストまたはロールで指定できます。
# 単一ホスト
mysql:
host: 1.1.1.1
# 複数ホスト
redis:
hosts:
- 1.1.1.1
- 1.1.1.2
# ロール指定
monitoring:
roles:
- web
- jobs
これでmrsk accessory start mysql
を実行して1.1.1.3のホストでMySQLサーバーを起動します。mrsk accessory
で利用可能な全コマンドを表示できます。
アクセサリのイメージは、publicなイメージか、自分たちのprivateレジストリでタグ付けされていなければなりません。
cronを使う
cronジョブ実行用のコンテナを利用できます。
servers:
cron:
hosts:
- 192.168.0.1
cmd:
bash -c "cat config/crontab | crontab - && cron -f"
上はcron設定がconfig/crontab
に保存されていることが前提です。
監査ブロードキャストを使う
デプロイやロールバックなどの監査をチャットルームなどにブロードキャストしたい場合は、監査のコード行に渡されるバイナリへのパスをaudit_broadcast_cmd
の第1引数に設定することでできます。
audit_broadcast_cmd:
bin/audit_broadcast
ブロードキャストコマンドは以下のようになります。
#!/usr/bin/env bash
curl -q -d content="[My App] ${1}" https://3.basecamp.com/XXXXX/integrations/XXXXX/buckets/XXXXX/chats/XXXXX/lines
これで、以下のような行がBasecampの事前設定済みチャットボットに投稿されます。
[My App] [dhh] Rolled back to version d264c4e92470ad1bd18590f04466787262f605de
パスやポートのカスタムヘルスチェック
MRSKはデフォルトでアプリケーションのポート3000の/up
に再度ヘルスチェックを行います。ポートやパスはhealthcheck
設定でカスタマイズできます。
healthcheck:
path: /healthz
port: 4000
これにより、/healthz
パスへのヘルスチェック用のtraefikラベル付きでアプリケーションが構成され、MRSKが実行するデプロイ前ヘルスチェックがポート4000の同じパスに対して実行されるようになります。
コマンド
サーバーでコマンドを実行する
以下の単発コマンドを実行できます。
# すべてのサーバーでコマンドを実行する
mrsk app exec 'ruby -v'
App Host: 192.168.0.1
ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
App Host: 192.168.0.2
ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
# primaryサーバーでコマンドを実行する
mrsk app exec --primary 'cat .ruby-version'
App Host: 192.168.0.1
3.1.3
# すべてのサーバーでコマンドを実行する
mrsk app exec 'bin/rails about'
App Host: 192.168.0.1
About your application's environment
Rails version 7.1.0.alpha
Ruby version ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
RubyGems version 3.3.26
Rack version 2.2.5
Middleware ActionDispatch::HostAuthorization, Rack::Sendfile, ActionDispatch::Static, ActionDispatch::Executor, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, ActionDispatch::RemoteIp, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, ActionDispatch::Callbacks, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ContentSecurityPolicy::Middleware, ActionDispatch::PermissionsPolicy::Middleware, Rack::Head, Rack::ConditionalGet, Rack::ETag, Rack::TempfileReaper
Application root /rails
Environment production
Database adapter sqlite3
Database schema version 20221231233303
App Host: 192.168.0.2
About your application's environment
Rails version 7.1.0.alpha
Ruby version ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-linux]
RubyGems version 3.3.26
Rack version 2.2.5
Middleware ActionDispatch::HostAuthorization, Rack::Sendfile, ActionDispatch::Static, ActionDispatch::Executor, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, ActionDispatch::RemoteIp, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, ActionDispatch::Callbacks, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ContentSecurityPolicy::Middleware, ActionDispatch::PermissionsPolicy::Middleware, Rack::Head, Rack::ConditionalGet, Rack::ETag, Rack::TempfileReaper
Application root /rails
Environment production
Database adapter sqlite3
Database schema version 20221231233303
# primaryサーバーでコマンドを実行する
mrsk app exec -p 'bin/rails runner "puts Rails.application.config.time_zone"'
UTC
SSH経由でインタラクティブにコマンドを実行する
サーバー上で、Railsコンソールやbashセッションなどの対話型コマンドを実行できます (デフォルトはprimary: 別のサーバーに接続するには--hosts
を使います)。
# アプリの直近のイメージから作った新規コンテナで
# 新しいbashセッションを開始する
mrsk app exec -i bash
# アプリが現在実行中のコンテナでbashセッションを開始する
mrsk app exec -i --reuse bash
# アプリの直近のイメージから作った新規コンテナで
# Railsコンソールを開始する
mrsk app exec -i 'bin/rails console'
コンテナの詳細な実行状態を表示する
mrsk details
を実行するとサーバーの状態を表示できます。
Traefik Host: 192.168.0.1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6195b2a28c81 traefik "/entrypoint.sh --pr…" 30 minutes ago Up 19 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp traefik
Traefik Host: 192.168.0.2
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
de14a335d152 traefik "/entrypoint.sh --pr…" 30 minutes ago Up 19 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp traefik
App Host: 192.168.0.1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
badb1aa51db3 registry.digitalocean.com/user/app:6ef8a6a84c525b123c5245345a8483f86d05a123 "/rails/bin/docker-e…" 13 minutes ago Up 13 minutes 3000/tcp chat-6ef8a6a84c525b123c5245345a8483f86d05a123
App Host: 192.168.0.2
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1d3c91ed1f55 registry.digitalocean.com/user/app:6ef8a6a84c525b123c5245345a8483f86d05a123 "/rails/bin/docker-e…" 13 minutes ago Up 13 minutes 3000/tcp chat-6ef8a6a84c525b123c5245345a8483f86d05a123
mrsk app details
でアプリコンテナの情報だけを表示したり、mrsk traefik details
でTraefikの情報だけを表示したりすることも可能です。
不適切なデプロイをロールバックで修正する
不適切なデプロイに気づいたら、一時停止している古いコンテナイメージを再度アクティベートすることで即座にロールバックできます。
mrsk app containers
を実行すると、ロールバックできる古いコンテナを確認できます。
表示内容はmrsk app details
に似ていますが、古いコンテナもすべて含まれます。出力は以下のようになります。
App Host: 192.168.0.1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1d3c91ed1f51 registry.digitalocean.com/user/app:6ef8a6a84c525b123c5245345a8483f86d05a123 "/rails/bin/docker-e…" 19 minutes ago Up 19 minutes 3000/tcp chat-6ef8a6a84c525b123c5245345a8483f86d05a123
539f26b28369 registry.digitalocean.com/user/app:e5d9d7c2b898289dfbc5f7f1334140d984eedae4 "/rails/bin/docker-e…" 31 minutes ago Exited (1) 27 minutes ago chat-e5d9d7c2b898289dfbc5f7f1334140d984eedae4
App Host: 192.168.0.2
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
badb1aa51db4 registry.digitalocean.com/user/app:6ef8a6a84c525b123c5245345a8483f86d05a123 "/rails/bin/docker-e…" 19 minutes ago Up 19 minutes 3000/tcp chat-6ef8a6a84c525b123c5245345a8483f86d05a123
6f170d1172ae registry.digitalocean.com/user/app:e5d9d7c2b898289dfbc5f7f1334140d984eedae4 "/rails/bin/docker-e…" 31 minutes ago Exited (1) 27 minutes ago chat-e5d9d7c2b898289dfbc5f7f1334140d984eedae4
上の例ではe5d9d7c2b898289dfbc5f7f1334140d984eedae4
が直近のバージョンであることがわかるので、ここにロールバック可能です。
mrsk rollback e5d9d7c2b898289dfbc5f7f1334140d984eedae4
を実行してロールバックすると、6ef8a6a84c525b123c5245345a8483f86d05a123
が停止してe5d9d7c2b898289dfbc5f7f1334140d984eedae4
が起動します。古いコンテナも利用可能な状態になっているので、非常に迅速に行われます。レジストリからのダウンロードは発生しません。
mrsk deploy
を実行すると、デフォルトでは3日後に古いコンテナが削除されるのでご注意ください。
削除を実行してサーバーをクリーンアップする
Traefik、コンテナ、イメージ、レジストリセッションを含むアプリケーション全体を削除する場合はmrsk remove
を実行します。これにより、サーバーをクリーンにできます。
ロック
コンカレントな実行が安全でないコマンドは、実行中にデプロイロックを取得します。このロックは、primaryサーバー上のmrsk_lock
ディレクトリです。
ロックの状態は以下で確認できます。
mrsk lock status
Locked by: AN Other at 2023-03-24 09:49:03 UTC
Version: 77f45c0686811c68989d6576748475a60bf53fc2
Message: Automatic deploy lock
以下のようにロックを手動で取得・解除することも可能です。
mrsk lock acquire -m "Doing maintanence"
mrsk lock release
MRSKの開発状況
これはベータ版ソフトウェアです。コマンドは今後変更される可能性があります。ただし37signalsでは本番運用しています。
ライセンス
MRSK is released under the MIT License.
関連記事
The post mrsk gem README: 37signalsの多機能コンテナデプロイツール(翻訳) first appeared on TechRacho.
概要
MITライセンスに基づいて翻訳・公開いたします。
本記事公開時点のバージョン: Release v0.10.1 · mrsked/mrsk