Azure Web Appsお勉強メモ(8)App Service 内のコンテナーからネットワーク共有としての Azure Storageにアクセスする

はじめに

先日からAzure Web Appsをお勉強することをやっています。今回は、先日GAとなったApp Service 内のコンテナーからネットワーク共有としての Azure Storageにアクセスすることをやってみます。具体的には、Railsアプリのログ出力先をAzureファイル共有に指定して、ログが出力されることを確認します。

azure.microsoft.com

これまでの内容は以下を参照してください。

主に参考となる記事

以下のドキュメントを参考に進めていきます。

docs.microsoft.com

日本語版では2021年8月29日時点でまだ「プレビュー」という記載があるのですが、英語版ではAzure Portal上での設定方法もあるので、今回は英語版のもので進めていきます。

docs.microsoft.com

Azureファイル共有を作成する

Azure Portal上からAzureファイル共有を作成します。

docs.microsoft.com

今回はRailsのログを格納することを目的としていますので「railslogs」を作成します。

f:id:miyohide:20210829143710p:plain

その後、logsディレクトリを作成し、その下にファイルを出力するようにします。

マウントする

Azure Web Appsからマウント設定をします。パスのマッピングのところをクリックして「新しいAzure Storageマウント」をクリックします。

f:id:miyohide:20210829144216p:plain

必要な項目を入力します。

f:id:miyohide:20210829144117j:plain

マウントできているか確認します。Dockerイメージの中にSSHログインの機能を設定していたらdf -hコマンドを発行できます。SSHログインの機能については以前やりました。

miyohide.hatenablog.com

実際にdf -hを実行してみると、マウントされていることがわかります。

f:id:miyohide:20210829144736j:plain

Railsのログの出力先を設定する

Railsのログ出力先の変更は、config/environments/production.rbに対して以下の設定を追加することで実現します。

  config.paths['log'] = "/mylogs/logs/production.log"

以下を参考にしました。

stackoverflow.com

今回は、マウントポイントの下にlogsというディレクトリを作成して、その下にproduction.logを出力するようにします。

動作確認

Azure Web AppsにデプロイしたRailsアプリにアクセスして、ログがAzureファイル共有に出力されることを確認します。アプリにアクセスすると...pruduction.logが出力されていることが確認できました。

f:id:miyohide:20210829145852p:plain

ログも確認しましたが、見慣れたRailsのログでした。

(省略)
I, [2021-08-29T04:46:57.463024 #1]  INFO -- : [3621dd8c-e93b-4772-89f8-92626e664110] Started POST "/todos" for xxx.xxx.xxx.xxx at 2021-08-29 04:46:57 +0000
I, [2021-08-29T04:46:57.471267 #1]  INFO -- : [3621dd8c-e93b-4772-89f8-92626e664110] Processing by TodosController#create as HTML
I, [2021-08-29T04:46:57.480300 #1]  INFO -- : [3621dd8c-e93b-4772-89f8-92626e664110]   Parameters: {"authenticity_token"=>"[FILTERED]", "todo"=>{"title"=>"title1", "body"=>"body1"}, "commit"=>"Create Todo"}
I, [2021-08-29T04:46:57.718283 #1]  INFO -- : [3621dd8c-e93b-4772-89f8-92626e664110] Redirected to https://app-foobar.azurewebsites.net/todos/1
I, [2021-08-29T04:46:57.725135 #1]  INFO -- : [3621dd8c-e93b-4772-89f8-92626e664110] Completed 302 Found in 240ms (ActiveRecord: 229.1ms | Allocations: 1790)

Azureの各種リソースをTerraformで構築する(2) Azure Key Vaultに登録したデータを使ってAzure Database for PostgreSQLを作成する

はじめに

先日、Azureの各種リソースをTerraformで構築する方法を記しました。

miyohide.hatenablog.com

今回は、このお話の続きです。

以下のエントリーでAzure KeyVaultをSpring Bootで書いたアプリケーションで使う方法を記しました。

miyohide.hatenablog.com

この記事ではデータベースを手で作成し、ユーザやパスワードはAzure Key Vaultに別途登録したのですが、何かと手間です。

そこで、あらかじめAzure Key Vaultに登録しておいたユーザやパスワードを使ってデータベースをTerraformで作成する方法を記します。

TerraformでAzure Key Vaultのシークレットデータを読み込む

Terraformで既存のAzure Key Vaultのシークレットデータを読み込むには、Data Sourceのazurerm_key_vaultとazurerm_key_vault_secretを使うと良さそうです。

対象のKey Vaultをazurerm_key_vaultで指定します。

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault

azurerm_key_vaultで得られたidを使ってazurerm_key_vault_secretから対象のデータを取得します。

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault_secret

具体的な実装は以下の通り。

data "azurerm_key_vault" "keyvault" {
  name = var.keyvault_name
  resource_group_name = var.keyvault_resource_group
}

data "azurerm_key_vault_secret" "database-user" {
  name = "app-database-user"
  key_vault_id = data.azurerm_key_vault.keyvault.id
}

data "azurerm_key_vault_secret" "database-password" {
  name = "app-database-password"
  key_vault_id = data.azurerm_key_vault.keyvault.id
}

ここでは、Azure Key Vaultのシークレットに登録しているapp-database-userapp-database-passwordを使ってAzure Database for PostgreSQLを作成します。

f:id:miyohide:20210822151209p:plain

なお、Azure Key Vaultにはバージョンという概念があります。

docs.microsoft.com

同時に複数のバージョンを有効化することができるのですが、複数のバージョンを有効化したままでは今回の処理はうまく動きませんでした。どれか一つだけを有効化した方が良いかなとおもます。

f:id:miyohide:20210822155844j:plain

Azure Database for PostgreSQLの作成

TerraformでAzure Database for PostgreSQLを作成する方法は、以下のドキュメントを参考にしました。

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_database

ユーザやパスワードはAzure Key Vaultのデータを使います。ユーザはdata.azurerm_key_vault_secret.database-user.value、パスワードはdata.azurerm_key_vault_secret.database-password.valueと指定してあげればOKです。

具体的な実装は以下の通りです。

resource "azurerm_postgresql_server" "pg-server" {
  name = var.postgresql_server_name
  resource_group_name = azurerm_resource_group.rg.name
  location = azurerm_resource_group.rg.location

  administrator_login = data.azurerm_key_vault_secret.database-user.value
  administrator_login_password = data.azurerm_key_vault_secret.database-password.value

  sku_name = var.postgresql_sku_name
  version = var.postgresql_version

  storage_mb = var.postgresql_storage

  public_network_access_enabled = true
  ssl_enforcement_enabled = true
  ssl_minimal_tls_version_enforced = "TLS1_2"
}

resource "azurerm_postgresql_database" "pg-db" {
  name = "app_production"
  resource_group_name = azurerm_resource_group.rg.name
  server_name = azurerm_postgresql_server.pg-server.name
  charset = "utf8"
  collation = "Japanese_Japan.932"
}

変数の利用

上記の例でvar.からはじまるものはTerraformの変数の機能を使っています。

www.terraform.io

今回は以下のような記述をvariables.tfとして記述しました。

variable "keyvault_name" {
  type = string
}

variable "keyvault_resource_group" {
  type = string
}

variable "postgresql_server_name" {
  type = string
}

variable "postgresql_version" {
  type = string
  default = "11"
}

variable "postgresql_sku_name" {
  type = string
  default = "B_Gen5_1"
}

variable "postgresql_storage" {
  type = number
  default = 5120
}

実装の全体と実行

最終的な実装は以下の通りになりました。

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 2.65"
    }
  }

  required_version = ">= 0.14.9"
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "rg-railsapp"
  location = "japaneast"
}

data "azurerm_key_vault" "keyvault" {
  name = var.keyvault_name
  resource_group_name = var.keyvault_resource_group
}

data "azurerm_key_vault_secret" "database-user" {
  name = "app-database-user"
  key_vault_id = data.azurerm_key_vault.keyvault.id
}

data "azurerm_key_vault_secret" "database-password" {
  name = "app-database-password"
  key_vault_id = data.azurerm_key_vault.keyvault.id
}

resource "azurerm_postgresql_server" "pg-server" {
  name = var.postgresql_server_name
  resource_group_name = azurerm_resource_group.rg.name
  location = azurerm_resource_group.rg.location

  administrator_login = data.azurerm_key_vault_secret.database-user.value
  administrator_login_password = data.azurerm_key_vault_secret.database-password.value

  sku_name = var.postgresql_sku_name
  version = var.postgresql_version

  storage_mb = var.postgresql_storage

  public_network_access_enabled = true
  ssl_enforcement_enabled = true
  ssl_minimal_tls_version_enforced = "TLS1_2"
}

resource "azurerm_postgresql_database" "pg-db" {
  name = "app_production"
  resource_group_name = azurerm_resource_group.rg.name
  server_name = azurerm_postgresql_server.pg-server.name
  charset = "utf8"
  collation = "Japanese_Japan.932"
}

あとはこれを実行します。

variables.tfdefaultを指定していない項目に対して値を入力すると...

f:id:miyohide:20210822153419j:plain

無事作成されました。

f:id:miyohide:20210822153534p:plain

接続

接続してみます。Cloud Shellから接続するときはAzure Database for PostgreSQLの設定で「Azureサービスへのアクセスを許可」を「はい」に変更する必要があります。

f:id:miyohide:20210822153757j:plain

ユーザやパスワード、データベースを指定すると無事接続できました。

f:id:miyohide:20210822154309p:plain

注意点

最初、データベースの作成時にcollationja_JP.utf8に指定したら以下のエラーメッセージが出ました。

azurerm_postgresql_database.pg-db: Creating...
azurerm_postgresql_database.pg-db: Still creating... [10s elapsed]
╷
│ Error: Code="InvalidDatabaseCollation" Message="The provided database collation is invalid."
│
│   with azurerm_postgresql_database.pg-db,
│   on main.tf line 50, in resource "azurerm_postgresql_database" "pg-db":
│   50: resource "azurerm_postgresql_database" "pg-db" {

いろいろと調べてみると、Azure Database for PostgreSQLWindows上で動いているようで、そのためにja_JP.utf8は使えないそうです。

asazure.hatenablog.jp

lets.postgresql.jp

上で接続結果の画像を載せましたが、compiled by Visual C++ build 1800, 64-bitとあることからもWindowsベースで動いているような気がします。

Azure Web Appsお勉強メモ(7)データベース接続情報などをAzure Key Vaultから取得する

はじめに

先日からAzure Web Appsをお勉強することをやっています。今回は、これまでとはちょっと毛色を変えて、データベース接続情報などをAzure Key Vaultから取得することをやってみます。

これまでの内容は以下を参照してください。

参考となる記事

パスワードなどを一元管理するのに、Azure Key Vaultというサービスがあります。

docs.microsoft.com

これをSpring Bootで使う上でのチュートリアルも以下で公開されています。

docs.microsoft.com

今回はこのチュートリアルをベースに実施してみます。

前提条件

以下の環境で実装しました。

  • Spring Boot 2.5.3
  • PostgreSQL 13.3
  • Azure Key Vault Secrets Spring Boot starter client library for Java 3.6.0

Azure Key Vaultからデータを読み取る

上記のチュートリアルのとおりやっていけばAzure Key Vaultからデータを取得することができますが、チュートリアルはコマンドでやっているので、ちょっとわかりにくいです。Azure Portalでは以下の感じで設定します。

まずは動かしているAzure Web AppsでIDの設定を「オン」にします。

f:id:miyohide:20210815153719p:plain

次にAzure Key Vaultのアクセスポリシーにて一覧と読み込みの権限を付与します。上記のIDの設定を行うことで、Azure Web appsの名前でサービスプリンシパルが作られているので、それに権限を付与してあげれば良いです。

f:id:miyohide:20210815153959p:plain

チュートリアルでは、application.propertiesにテナントIDやらをそのまま書き込んでいますが、それだとAzure Key Vaultにパスワードなどを格納する意味はないので、環境変数を参照するようにします。

azure.keyvault.client-id=${KEYVAULT_CLIENT_ID}
azure.keyvault.enabled=true
azure.keyvault.tenant-id=${KEYVAULT_TENANT_ID}
azure.keyvault.uri=${KEYVAULT_URL}

なお、Azure Key Vault Secrets Spring Boot starter client library for Javaのドキュメントにはclient-idtenant-idの指定はしなくてもよいみたいな記述があるので、ひょっとしたら不要かも...。とりあえずここでは指定しておきます。

あとはこれらの環境変数をAzure Web Apps上のアプリケーション設定で設定してあげれば良いです。

f:id:miyohide:20210815154909p:plain

プログラムからAzure Key Vaultに登録したシークレットの値を見るためには、以下のような記述をすれば良いようです。

@Value("${シークレットの名前}")
private String secretValue;

これでsecretValueにシークレットの値が入ります。

データベースの接続情報をAzure Key Vaultから取得してプログラムに反映する。

上記の作業でAzure Key Vaultから値を読み取ることができました。次はデータベースの接続情報をAzure Key Vaultから取得したいと思います。以下のようにユーザー名やパスワード、接続先を設定しておきます。

f:id:miyohide:20210815155755p:plain

Spring Bootにおいて、データベースの接続先情報はapplication.propertiesにてspring.datasource.urlなどで指定することが一般的です。

docs.spring.io

今回のようにプログラムから設定するにはどうすればいいんだろう?と思っていたら、ちょうどよい記事がありました。

www.baeldung.com

この記事を参考に、以下のように実装しました。

package com.github.miyohide.appwithkeyvault;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {
    @Value("${app-database-url}")
    private String databaseUrl;
    @Value("${app-database-user}")
    private String databaseUser;
    @Value("${app-database-password}")
    private String databasePassword;

    @Bean
    public DataSource getDataSource() {
        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
        dataSourceBuilder.url(this.databaseUrl);
        dataSourceBuilder.username(this.databaseUser);
        dataSourceBuilder.password(this.databasePassword);

        return dataSourceBuilder.build();
    }
}

あとはプログラムをデプロイして動作を確認して、データベースから値を取得することが確認できればOKです。

f:id:miyohide:20210815160606p:plain

ソースコード

ソースコードはこちら。

github.com

Azureの各種リソースをTerraformで構築する(超初級編)

今日は小ネタ。ワクチン接種したら微妙に腕が痛くてあまり何もする気が起きなかった。

はじめに

これまでAzureの各種リソースを構築する際はAzure Portal上で作業をしていました。はじめての構築時はわかりやすいのですが、わかりきった内容を作る場合は色々とまどろっこしいものです。AzureにはARMテンプレートという機能があり、ポータルからエクスポートもできるのですが、JSON形式でメンテナンスがちょっと大変な感じです(個人の感想です)。

docs.microsoft.com

各種リソースのメニューでARMテンプレートの出力ができるので、お手軽ではあります。

f:id:miyohide:20210808173256p:plain

そこでここではTerraformというツールを使って各種リソースを構築してみることにします。

www.terraform.io

Azure上でのTerraform

新しいツールを利用するとき環境構築が面倒くさいのですが、Azure Cloud ShellにはすでにTerraformがインストールされているので今回はCloud Shell上で実行してみることにします。

f:id:miyohide:20210808173801p:plain

ドキュメントもあります。

docs.microsoft.com

どういうことができるかは、まずはTerraformのWebページ上にあるチュートリアルをやって理解することにします。

learn.hashicorp.com

リソースグループを作成する

まずは簡単にリソースグループを作成してみます。こんな感じのスクリプトを用意します。

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 2.65"
    }
  }

  required_version = ">= 0.14.9"
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "rg-railsapp"
  location = "japaneast"
}

あとは、これをAzure Cloud Shellにアップロードして、terraform initterraform applyを実行します。

f:id:miyohide:20210808174228p:plain

プロンプトでDo you want to perform these actions(これらの処理を実行しても良い?)と聞かれるのでyesと入力するとリソースグループが作成されます。

f:id:miyohide:20210808174504p:plain

Azure Container Registryを作成する

次にAzure Container Registryを作成します。先程作成したスクリプトを以下のように更新します。

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 2.65"
    }
  }

  required_version = ">= 0.14.9"
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "rg-railsapp"
  location = "japaneast"
}

# Create an Azure Container Registry
resource "azurerm_container_registry" "acr" {
  name                     = "crmiyohiderailsapp"
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = azurerm_resource_group.rg.location
  sku                      = "Basic"
  admin_enabled            = true
}

resource_group_namelocationは先程作成したリソースグループのものをazurerm_resource_group.rgを使って参照することができるようです。これをAzure Cloud Shellにアップロードしてterraform applyを実行します。

f:id:miyohide:20210808175351p:plain

すでにあるリソースグループに対して変更は行われず、追加でAzure Container Registryを作成します。

f:id:miyohide:20210808175527p:plain

削除

削除はterraform destroyを実行すればOKです。

f:id:miyohide:20210808175703p:plain

ポータル上でも確認してみます。無事削除されていることがわかります。

f:id:miyohide:20210808175757p:plain

参考資料

Terraformの公式にAzureの各種リソースを扱うためのドキュメントが整備されているので、これをみて色々とやってみると良いかと思います。

https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs

Azure Web Appsお勉強メモ(6)Azure Container RegistryにpushしたらAzure Web Appsにデプロイする

はじめに

先日からAzure Web AppsにRailsアプリを動かすことをやっています。先日の記事でGitHub Actionsを使ってDockerイメージを作成してAzure Container Registryにpushすることはできました。

miyohide.hatenablog.com

今回は、Azure Web Appsへのデプロイを自動化します。

これまでの内容は以下を参照してください。

参考となる記事

何か参考になる記事はないものかと探していたら、マイクロソフトが以下の記事を公開していました。

docs.microsoft.com

この中でも、Azure Container RegistryのWebHookの機能がお手軽にできそうです。早速やってみます。

WebHookを作成する

上記の記事の通りに以下のコマンドをCloud Shellで実行します。

ci_cd_url=$(az webapp deployment container config --name <app-name> --resource-group <group-name> --enable-cd true --query CI_CD_URL --output tsv)

az acr webhook create --name <webhook-name> --registry <registry-name> --resource-group <group-name> --actions push --uri $ci_cd_url --scope '<image>:<tag>'

scopeの部分に何を設定すれば良いかわかりませんでしたが、image名:*で任意のタグでWebHookが起動するようです。

docs.microsoft.com

実際に作成してみると、以下のようにWebHookが作成されました。

f:id:miyohide:20210801140411p:plain

新しいバージョンにならない?

早速、新しいバージョンを作成してpushします。WebHookのログをみると、新しいバージョンを検知しているのですが、アプリは最新版になっていませんでした。

f:id:miyohide:20210801141236p:plain

Web Appsのデプロイログを見ると、WebHookの起動時刻である13:25(JST)(黒い画面では04:25(UTC))前後にDockerイメージが最新版かどうか見にいっているのですが、タグが古いままになっています(Web Appsのデプロイログでは0.0.14をみているが、WebHookでは0.0.15)。

f:id:miyohide:20210801141815j:plain

Azure Container Registryにpushしたときに発行されるWebHookにtagもついているのでAzure Web Apps側で見れないことはないと思うのですが、今のところ挙動としてはWebHook内のtagを反映してくれないようです。

docs.microsoft.com

対策

ということで、対策です。GitHub Actionsでpushしているバージョン番号付きのDockerイメージとは別にlatestとtagをつけたものを作成・pushすることにします。Azure Web Apps側ではlatestを見るようにします。

GitHub Actionsでの記述

GitHub Actionsでは以下の記述を追記します。

# 省略
# これまで設定していたバージョン番号付きのDockerイメージの生成
docker build -f Dockerfile.prd -t ${{ secrets.REGISTRY_SERVER }}/rails_template_sqlite3:$IMAGE_TAG .
docker push ${{ secrets.REGISTRY_SERVER }}/rails_template_sqlite3:$IMAGE_TAG
# latestタグをつける
docker tag ${{ secrets.REGISTRY_SERVER }}/rails_template_sqlite3:$IMAGE_TAG ${{ secrets.REGISTRY_SERVER }}/rails_template_sqlite3:latest
# latestタグをpushする
docker push ${{ secrets.REGISTRY_SERVER }}/rails_template_sqlite3:latest
# 省略

Azure Web Apps側の設定

タグをlatestに設定します。

f:id:miyohide:20210801142535j:plain

この時点で、Azure Container RegistryのWebHookが新しく作られました。先に作った二重起動になるので削除しておきます。

f:id:miyohide:20210801142736p:plain

再検証

ここまでできたので、再度新しいバージョンを作成して実行してみます。すると、Dockerイメージがpushされた時点でWebHookが起動されます。

f:id:miyohide:20210801142918p:plain

数秒後に、Azure Web Appsにおいて新しいバージョンがデプロイされたことを検知してイメージをpullしてくれました。

f:id:miyohide:20210801143054j:plain

もちろん、アプリも新しいバージョンに置き換わりました。

Azure Web Appsお勉強メモ(5)Azure Web AppsにてデプロイしたDockerイメージにSSH接続する

はじめに

先日からAzure Web AppsにRailsアプリを動かすことをやっています。昨日のエントリーでAzure Web Apps上でRailsアプリを動かす方法を記しました。

miyohide.hatenablog.com

無事、動かすことができたのですがデバッグなど何かとSSHができた方が嬉しいのでSSH接続する方法を記します。

昔「infrastructure as codeとかでマシンにSSHログインしたら負けと思え」と言われたことがあるのですが、あまり気にしないことにします。

これまでの内容は以下を参照してください。

参考となる資料

マイクロソフトが公開している以下のドキュメントに「SSHを有効にする」という記述があるのでこれを参考にします。

docs.microsoft.com

上記ドキュメントの記述内容はapkコマンドを使っていることからAlpine LinuxベースのDockerイメージを使ったものなので、バージョン番号しか書かれていなかったり、-slimとついているDockerイメージを使っている場合は若干コマンドが異なります。昨日のエントリーでの例もruby:3.0.2のDockerイメージを使っているので、上記のドキュメントから若干修正が必要となります。

設定

やるべきことは以下の5点です。

  • openssh-serverをインストールする
  • パスワードを変更する
  • SSH設定ファイル(sshd_config)を作成し、/etc/ssh/以下に格納する
  • SSHサーバーを起動する
  • ポート番号2222を開ける

一個ずつやっていきます。

openssh-serverをインストールする

Dockerfile内で以下の記述を追加するだけです。

RUN apt-get update && apt-get install -y openssh-server

パスワードを変更する

これはマイクロソフトが公開しているドキュメントに書いてあるコマンドをそのまま実行します。具体的にはDockerfile内で以下の記述を追加します。

RUN echo "root:Docker!" | chpasswd

SSH設定ファイル(sshd_config)を作成し、/etc/ssh/以下に格納する

これもマイクロソフトが公開しているドキュメントと同じようにDockerfileに記述します。プロジェクトのルートにsshd_configを作成し、中身をマイクロソフトが公開しているドキュメントからコピペ。Dockerfile内で以下の記述を追加します。

COPY sshd_config /etc/ssh/

SSHサーバーを起動する

Dockerfile内のENTRYPOINTで指定したシェルスクリプトentrypoint.shに以下の記述を追加します。

service ssh start

ポート番号2222を開ける

ポート番号2222をDockerfile内のEXPOSEに追記します。元々は

# 変更前
EXPOSE 3000

となっていたのを以下のようにするだけです。

# 変更後
EXPOSE 3000 2222

実行

ここまで設定できたら、あとはDockerイメージを作成してAzure Web Appsにデプロイします。デプロイが完了したら、Azureポータルから「開発ツール」の「SSH」から「移動」をクリックします。

f:id:miyohide:20210725163914p:plain

すると別のタブが開いて、SSH接続できます。

f:id:miyohide:20210725164124p:plain

Dockerイメージ内に入っているだけなので、ディレクトリ構成もDockerイメージと同じです。

f:id:miyohide:20210725164329p:plain

Azure Web AppsでRails 6.1アプリをproduction環境で動かす(2021年7月版)

はじめに

Azure Web Appsの勉強をしているときに、実際に動かすアプリが欲しかったのでRailsでアプリを動かそうとしたら微妙にハマったので備忘録として記します。

前提事項

RubyRailsのバージョンは以下のバージョンで検証しました。

Azure Web AppsはRubyを動かす環境が用意されていますが、実際に動くバージョンが2021年7月24日時点で2.6と古いです。

f:id:miyohide:20210724210055p:plain

最新版で動かそうとしたらDockerイメージを動かす方が良いでしょう。

docs.microsoft.com

Dockerfileを作成する

Dockerfileの書き方のサンプルはDockerのドキュメントとして以下に記述があるのですが、これも扱っているバージョンが古いです。

docs.docker.jp

今はWebpackerを使う関係上Node.jsが必要なのですが、Node.jsが必要なのはイメージを作成するだけなのでマルチステージビルドという機能を使います。

docs.docker.jp

結果として、以下の記述となりました。

FROM node:14.17.0-slim as node
FROM ruby:3.0.2

# NodeとYarnのインストール
ENV YARN_VERSION 1.22.5
RUN mkdir -p /opt

COPY --from=node /opt/yarn-v$YARN_VERSION /opt/yarn
COPY --from=node /usr/local/bin/node /usr/local/bin/
COPY --from=node /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
RUN ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
  && ln -s /opt/yarn/bin/yarn /usr/local/bin/yarnpkg \
  && ln -s /usr/local/bin/node /usr/local/bin/nodejs \
  && ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
  && ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx

WORKDIR /app

COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
COPY yarn.lock /app/yarn.lock
# developmentとtestのgemはインストールしない
RUN bundle config set --local without 'development test'
RUN bundle install
RUN yarn install

COPY . /app

RUN RAILS_ENV=production bin/rails assets:precompile

ENV RAILS_ENV=production

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

CMD [ "rails", "server", "-b", "0.0.0.0" ]

許可するホスト名の設定

上記でRailsアプリをAzure Web Apps上で動かそうとするとBlocked host:と書かれたエラーメッセージが出ます。対応としては、以下のドキュメントにあるようにconfig.hostsにAzure Web Appsのドメインを追加するだけです。

guides.rubyonrails.org

具体的には、config/environments/production.rbRails.application.configure doの内側に以下の記述を追加します。

config.hosts << ".azurewebsites.net"

最初にピリオドをつけることで、すべてのサブドメインを許可することができます。

環境変数の設定

環境変数の設定も必要です。今回設定したのは以下のものです。

  • RAILS_LOG_TO_STDOUT
    • ログを標準出力に出力する。値は1でもtrueでも何でも良い。設定されていることが大事。
  • RAILS_MASTER_KEY
    • credentialファイルのマスターキー。ローカルにあるconfig/master.keyの中身の値を設定する。
  • RAILS_SERVE_STATIC_FILES
    • Railsに静的ファイルの配信をお願いする。値は1でもtrueでも何でも良い。設定されていることが大事。
  • WEBSITES_PORT
    • Railsアプリが開いているポート番号3000を指定。

少しハマったのは、RAILS_MASTER_KEYの設定です。これを設定してなかったので、アプリにアクセスしたときにAn unhandled lowlevel error occurred. The application logs may have details.と出てしばらく悩みました。credentialの設定はRails 4.1ぐらいからいろいろと変更されていたので、最新のRailsではどのような設定をするかよくわかりませんでした。

ここら辺は以下のRails Guideを参照するか

railsguides.jp

パーフェクトRuby on Rails 【増補改訂版】のP152ぐらいからの記述に詳しく書かれていますので、参照されることをお勧めします。

またWEBSITES_PORTは以下のドキュメントには指定する必要がある旨が書かれているので設定していますが、私の場合、設定しなくても動くことが多いです。必要な場合と不要な場合の条件についてはよくわかっていません。

docs.microsoft.com

結果としてAzure Web Appsの「アプリケーション設定」は以下のようになりました。

f:id:miyohide:20210724213006p:plain

上記の設定でRails 6.1で作られたアプリをAzure Web Appsで動かすことができました。