📚

ハッカソン中にlaravelをazureで12時間以上かけてでぷろいした話

2024/10/08に公開

はじめに

学部3年のよわよわ学生が、AzureでLaravelをデプロイする方法をまとめました。
学生のハッカソン中にやったことをまとめています。
12時間以上やったので,どれが正解かわからないところの方が多いです...
蛇足が多いですが、ご容赦ください。m(__)m
構成図はこんな感じです。

※以下の命名規則はかなり適当になっております。ちゃんと調べて命名しましょう。
名前付け規則を定義する
Azure リソースの省略形の例

前提

Azureサブスクリプションを用意する。
※今回は学生用のプランを使用

https://azure.microsoft.com/ja-jp/free/students/

環境【Mac】

  • Docker Desktop
  • ターミナル(Mac に入っているもので OK)

https://docs.docker.com/desktop/install/mac-install/

Azure Data Studio(任意)
https://azure.microsoft.com/ja-jp/products/data-studio

Azureでデプロイ

Azureにアクセスし、ログインします。

web appsを作成

プロジェクト単位でリソースグループを作成する。
次にインスタンスの詳細の名前を書き、ランタイムスタックをPHP8.3に設定します。
(画像は古いだけで今は8.3なので8.3にしましょう)
リージョンはJapan Eastに設定します。
価格プランはF1を選択します。

確認して作成を押します。
次に別サービスDatabase for my sqlを作成します。

Database for my sqlを作成

検索でAzure Database for MySQLを検索します。
Azure Database for MySQL のフレキシブル サーバーを立てます。
赤枠のほうを選択します。

簡易作成を選択します(最近初めて知りました)
前は、単一サーバーがあったんですが、廃止になったのでこちらを使います

リソースグループは先ほど作成したものを選択します。
DBサーバーとWebAppは同じリソースグループにすることが大事です。
(画像のリソースグループが違うのは、ハッカソンの時とその後もう一回やった時の画像なので違うだけです。)
regionはJapan Eastに設定します。
サーバー名、ユーザー名、パスワードを設定します。
パスワードは覚えておく必要があるので、脳内メモしておきます。(どこかに書いておく)
「確認および作成」を押します。

https://learn.microsoft.com/ja-jp/azure/mysql/flexible-server/tutorial-php-database-app#configure-tlsssl-certificate

デプロイセンターでGitHubからデプロイ

AzureのWebAppでデプロイセンターでデプロイしたいリポジトリを選択します。
設定が終わったら保存を押します。
GitHub Actionに移動して一旦デプロイが完了できたのを確認します。

環境変数を設定

Web Appの設定で環境変数を設定します。
*がつく数字はテーブルの下に入力する値を示します。
環境変数を以下になります

名前
APP_DEBUG true
APP_ENV production
APP_KEY 1*
DB_CONNECTION mysql
DB_DATABASE 2*
DB_HOST 3*
DB_PASSWORD 4*
DB_USERNAME 5*
MYSQL_ATTR_SSL_CA /home/site/wwwroot/DigiCertGlobalRootCA.crt.pem

以下に値の場所を書きます。
1にはコマンドラインで php artisan key:generate --show で生成したキーを入力

運用環境のシナリオでは、コマンドラインで php artisan key:generate --show を使って、デプロイ用に特別に生成する必要があります。
参考元

2にはDBサーバーで作成したDB名
2の補足
以下の写真のように追加を押して、データベースを作成します。今回はDB名をlifeとしました。

3には作成したDBサーバーのサーバ名
4には自分が設定したDBサーバーのパスワード
5にが自分が設定したDBサーバーのユーザー名
Azure Portalのdb for mysqlの概要に以下の画像あります

参考

上記を設定し終わったら適用を押します。

下記は設定しましたが設定する必要ない環境変数です

名前
PHP_COMPOSER_VERSION 2.6.2
SCM_DO_BUILD_DURING_DEPLOYMENT false

composerは、AzureのOryxが使っているバージョンと合わせる必要があります。

また、アプリ直下でDigiCertGlobalRootCA.crt.pemを作成してください。
このssl証明書はAzure Database for MySQLのフレキシブル サーバーに接続するために必要です。
ダウンロードをしてDigiCertGlobalRootCA.crt.pemをディレクトリ直下に書き込んでください
https://learn.microsoft.com/ja-jp/azure/mysql/flexible-server/how-to-connect-tls-ssl#download-the-public-ssl-certificate


また、「default」というファイルを作成し、ディレクト直下に以下の内容を記述してください。
下記はNginxの設定ファイルです。MSのサンプルをそのまま使っています。

default
server {
    #proxy_cache cache;
    #proxy_cache_valid 200 1s;
    listen 8080;
    listen [::]:8080;
    root /home/site/wwwroot/public;
    index  index.php index.html index.htm;
    server_name  example.com www.example.com; 
    port_in_redirect off;

    location / {            
        index  index.php index.html index.htm hostingstart.html;
        try_files $uri $uri/ /index.php?$args; # Changed for Laravel
    }

    # redirect server error pages to the static page /50x.html
    #
    #error_page   500 502 503 504  /50x.html; # Commented out for Laravel so that Laravel debug mode pages are shown
    location = /50x.html {
        root   /html/;
    }
    
    # Disable .git directory
    location ~ /\.git {
        deny all;
        access_log off;
        log_not_found off;
    }

    # Add locations of phpmyadmin here.
    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
        fastcgi_pass 127.0.0.1:9000;
        include fastcgi_params;
        fastcgi_param HTTP_PROXY "";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param QUERY_STRING $query_string;
        fastcgi_intercept_errors on;
        fastcgi_connect_timeout         300; 
        fastcgi_send_timeout           3600; 
        fastcgi_read_timeout           3600;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;
    }
}

参考

二つのファイルは以下のようになります。

次に、DBサーバーで設定/メットワーク「Azure 内の任意の Azure サービスにこのサーバーへのパブリック アクセスを許可する」をチェックを入れます。
保存してください

次にLaravelの/app/Providers/AppServiceProvider.phpに以下のコードを追加します。

AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Routing\UrlGenerator;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(UrlGenerator $url): void
    {
        if (env('APP_ENV') == 'production') {
            $url->forceScheme('https');
        }
    }
}

上記を追加することで、本番環境でhttpsを強制することができます。
上記を追加しないと、httpでアクセスしてしまい、Mixed Contentエラーが発生します。

workflowのyamlファイルを編集

全コピせずに書いてください。
nodeの記述を書き足しました。
client-idなどのAzureの情報は書き換えないでください。
Vscodeのローカルで.gtihub/workflows/~~.yamlを確認する場合、「GitHub Actions for VS Code」をインストールしてください。
GitHubのアカウントで認証を行なってください
GitHub Actions for VS Code

workflows/~~.yaml
name: Build and deploy PHP app to Azure Web App - laravel

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "8.3"

      - name: Check if composer.json exists
        id: check_files
        uses: andstor/file-existence-action@v1
        with:
          files: "composer.json"

      - name: Run composer install if composer.json exists
        if: steps.check_files.outputs.files_exists == 'true'
        run: composer validate --no-check-publish && composer install --prefer-dist --no-progress

      - name: Zip artifact for deployment
        run: zip release.zip ./* -r

      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v4
        with:
          name: php-app
          path: release.zip

+ node_build:
+   runs-on: ubuntu-latest
+   needs: build
+   steps:
+     - uses: actions/checkout@v3
+     - name: Clear npm cache and install dependencies
+       run: |
+         rm -rf node_modules
+         rm -f package-lock.json
+         npm install --prefer-offline
+ 
+     - name: Set up Node.js
+       uses: actions/setup-node@v3
+       with:
+         node-version: "v18.13.0"
+         cache: "npm"
+         cache-dependency-path: ./package-lock.json
+ 
+     - name: Check if package-lock.json exists
+       id: check_files
+       run: '[ -f "package-lock.json" ] && echo "File exists" || echo "File does not exist"'
+ 
+     - name: Generate package-lock.json if not exists
+       run: npm ci --prefer-offline
+ 
+     - name: npm install, npm run build
+       run: |
+         npm ci
+         npm run build --if-present
+         npm ci --production
+ 
+     - name: Zip artifact for deployment
+       run: zip -r node-app.zip . -x node_modules/\* .git/\*
+ 
+     - name: upload artifact for deployment job
+       uses: actions/upload-artifact@v4
+       with:
+         name: node-app
+         path: .

  deploy:
    runs-on: ubuntu-latest
+   needs: node_build
-   needs: build
    environment:
      name: "Production"
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
    permissions:
      id-token: write #This is required for requesting the JWT

    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v4
        with:
          name: php-app

      - name: Unzip artifact for deployment
        run: unzip release.zip

+     - name: Download artifact from node build job
+       uses: actions/download-artifact@v4
+       with:
+         name: node-app

      - name: Login to Azure
        uses: azure/login@v2
        with:
          client-id: ${{AZUREAPPSERVICE_CLIENTID }}
          tenant-id: ${{AZUREAPPSERVICE_TENANTID}}
          subscription-id: ${{ AZUREAPPSERVICE_SUBSCRIPTIONID}}

      - name: "Deploy to Azure Web App"
        uses: azure/webapps-deploy@v3
        id: deploy-to-webapp
        with:
          app-name: "laravel"
          slot-name: "Production"
          package: .


GitHub Actionでデプロイが完了したのを確認します。

ci/cdは成功してもAzure側で設定がきちんとできてないので、デプロイはできてません。

データベース スキーマの生成

Web Appのページに移動し、スキーマを生成します。
開発ツール/SSHを選択します。
そこで以下のコマンドを実行します。
まず初めにディレクトリに移動します。

cd /home/site/wwwroot

次に以下のコマンドを実行します。

php artisan migrate --force

これでデータベースのスキーマが生成されます。
以下のように表現されます。

確認する方法は二つあります。
1.Azure Data Studioを使って確認する
2.phpMyAdminを使って確認する
phpmyadominは環境変数を変更すれば使えるようになります。

Azure Data Studioを使って確認して作成を確認しました

サイト ルートの変更

Web appの構成でスタートアップコマンドを変更します。

以下のコマンドを入力します。

cp /home/site/wwwroot/default /etc/nginx/sites-available/default && nginx -s reload

入力し終わったら保存を押します。
もう一度GitHub Actionの「Re-run all jobs」を押します。
完了したらWeb Appのメニューの概要のURLをクリックして、サイトが表示されるか確認します。

Logの確認方法

私が知っている方法はふたつあります

  1. Azureのポータルから確認する
    監視/ログストリームを選択します。
    そこでログを確認することができます
  2. sshでログを確認する
    開発ツール/SSHを選択します。
    そこで以下のディレクトリに移動します。
cd /home/site/wwwroot/storage/logs

laravel.logを確認することができます。

cat laravel.log

そこでエラーが確認することができるので詰まった際は確認しましょう。

重要:リソース削除

リソースを削除しましょう。
ずっと使っているとお金がかかるので、削除するようにしましょう。
忘れずに行いましょう!!!

[リソース グループ] ページで、 [リソース グループの削除] をクリックします。
リソース グループの名前を入力して、削除を確定します。
[削除] をクリックします。
参考

まとめ

GitHub Issueでまさにこれ!って感じの問題が他の人も抱えていたので、助かりました。
log streamでエラーを見ながら格闘したことを書きました。設定だけで実際10時間ぐらい時間を取られました。
デプロイが大変だと思い知らせましたね。try&errorで進めていきました
ちょくちょく雑談的なことも書いてしまいましたが、この記事を読んでくれた方が少しでも助かれば幸いです。
記事に書く大事さを再認識しました。ハッカソンから月日を経ってもう一回しようとしたら、何をやったかわからなくなるので、記事に残すことの大事さを感じました。やり方忘れてしまってもう12時間ぐらいかけてデプロイをしました。これからは記事に残すことを心がけます。
まだまだ未熟なひよっこなので、間違いがあれば指摘していただけると幸いです。

参考文献

GitHub Actions VSCode 拡張の紹介
Azure App Service: Unable to deploy PHP 8.0-based applications with Composer enabled
laravel-tasks
How to Deploy Laravel App on Azure Linux App Service Using ZipDeploy in 7 Easy Steps
ファイル数が多いせいで時間のかかるGitHub Actionsのデプロイを短縮する
分かったうえではじめるCI/CD
Oryx configuration
暗号化された接続を使用して Azure Database for MySQL - フレキシブル サーバーに接続する
チュートリアル: Azure App Service で PHP (Laravel) と Azure Database for MySQL - フレキシブル サーバー アプリを構築する

Discussion