Technote

by sizuhiko

Next.js を standalone ビルドしたアプリで New Relic エージェントを動かす

こちらの記事は Next.js で作ったアプリケーションを AppRunner にデプロイする の続編となります。 前編を読まないとわからない内容ではないですが、もし良ければ事前に確認してください。

前の記事で Next.js を standalone ビルドしたアプリを App Runner にデプロイするところまで書きました。

そのアプリでテスト環境のとき New Relic エージェントを入れたいということでやってみたんですが、ものすごいハマりどころが多かったので誰かの役に立てばと思い記事にします。

エージェントのインストールと起動方法

New Relic の Node.js エージェントは node-newrelic というリポジトリにある OSS ライブラリです。 利用するときは以下のように Node.js の –require module オプションを使って起動するようです。

$ node -r newrelic your-program.js

Next.js で利用する場合の例として Next.js example projects というのも用意されていますが、今回は standalone モードでビルドされてますので、 Custom Next.js servers というところのやり方と一緒で結局 --require module モードで起動することになります。

やってみる

まず npm install newrelic でパッケージを追加しておいて、 Next.js のリポジトリにある standalone ビルドの Dockerfile で起動スクリプトを以下のように変更します。

# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output
ENV HOSTNAME="0.0.0.0"
CMD ["node", "-r", "newrelic", "server.js"]

はい、起動しません。

Error: Cannot find module ‘/app/nodemodules/lodash/lodash.js’. Please verify that the package.json has a valid “main” entry at Object. (/app/nodemodules/@newrelic/security-agent/lib/nr-security-agent/lib/core/commonUtils.js:20:16)

調べよう

newrelic/csec-node-agent という依存モジュールの package,json の中に lodash があるのを見つけました。

で、使っている場所はこの行なんですが、いやな使い方をしていますね。

const lodash = require('lodash')
// ここを
const isEmpty = require('lodash/isEmpty')

下のように記述してくれていれば良い(実際 isEmpty しか使ってない)のですけど… まぁとはいえ動きません。

まず何でかっていうと、そもそも Next.js は standalone モードでビルドされていて、コンテナサイズを小さくするために Next.js から依存関係にないパッケージは入りません。 つまり New Relic のエージェントを --require module モードで起動すると、依存しているパッケージがないので動かないという、まぁ至極その通りな感じであります。

で、いろいろネットの情報を調べていたら、サーバー起動する直前で npm i newrelic すると良いよというのを見つけました。 以下のソース

# Install the next.js plugin after it copies the standalone server and static bits to workdir
# I cannot figure out why If I just install `@newrelic/next` and add to project's package.json
# why it does not copy them over but it does not for some reason so we will add it after all the copying
# occurs
RUN npm i newrelic

USER nextjs

EXPOSE 3000

ENV PORT 3000

# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
ENV HOSTNAME="0.0.0.0"

CMD ["node", "-r", "newrelic", "server.js"]

なるほどねー、ってことでやってみました。

…. 動かない….

なんでかって言うと、僕らのアプリでは、依存関係で(厳密にいうと依存の依存に)すでに lodash があったんですね。つまりこの状況( /app/node_modules/lodash/ が存在する )で依存の依存で lodash 入れようと思ってもすでに入っているので、追加(上書き)では入りません。 まぁそうですよね。npm とはそういうものです。で、その lodash は standalone モードで使ってないモジュールは消されているので lodash.js という一等地の全部インポートファイルはありません。せめて require('lodash/isEmpty') なっていれば…(isEmptyはあった)。 とはいえ、他にも依存モジュールあったんで、lodash だけの問題とも言い切れませんね。

先人が通った道

Next.js に New Relic 導入し、docker コンテナの起動に失敗した話 に出会いました。 node_modules の下のファイルをコピーする….。まぁ動きそうな気はするけど、コピーはいやだなぁ….ということで違う方法を模索します。

過去には、Next.js 用のライブラリがあったようで、そのときの issue も見つけました。

でそのときの対応が node-newrelic リポジトリになるときのマイグレーション issue も見つけました。

ということで、何だか standalone モードへの対応は考慮されているようですが、前述のとおり Web アプリ側でも依存関係にあってエージェント側でも使っているみたいなケースでは失敗してしまうこともありえます。 僕がソースコードを見回った結果は lodash だけっぽかったので、そこだけ修正すれば大丈夫なのかもですけど。

グローバルインストールという脇道(ハック)

アプリケーションの下の node_modules だと入らないので、別のところでクリーンインストールすれば良いのでは?という結論に至りました。 とりあえずアプリと別のディレクトリを掘ってやってもよかったんですけど、面倒だったのでグローバルインストールを使います。

# Install dependencies only when needed
FROM base AS deps

# 長いので省略 一番下に追加
RUN npm i -g newrelic

マルチステージビルドの deps の最後でグローバルインストールします。 続いて standalone ビルドしたファイルをコピーした後で、グローバルインストールフォルダを丸っとコピーして持ってきます。 で、そこに NODE_PATH 環境変数を通すというハックを入れました。

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

COPY --from=deps /usr/local/lib/node_modules /usr/local/lib/node_modules
ENV NODE_PATH=/usr/local/lib/node_modules

おそらく gist の例とかは newrelic が依存しているライブラリを Next.js のアプリが使っていない前提で書かれていると思われる。

結局 newrelic が依存しているものを Next が良い感じに standalone ビルドすると当然 newrelic なんぞ?みたいになって動かないからな。ライブラリ作者はそこまで気が回ってないのだろう

グローバルはハックな方法だと思うけど、正しいやり方をサポートは対応してくれるんかな….

ライブラリは OSS なんで issue 書いてよ、というのは、まぁそのとおり(まだやってません、すみません)。

やってみる(2回目)

動きません….. 😭

Cannot find module ‘@newrelic/native-metrics’\nRequire stack:\n- /usr/local/lib/nodemodules/newrelic/lib/sampler.js\n- /usr/local/lib/nodemodules/newrelic/lib/agent.js\n- /usr/local/lib/node_modules/newrelic/index.js\n- internal/preload

Cannot find module ??なんですって?

"optionalDependencies": {
    "@contrast/fn-inspect": "^4.2.0",
    "@newrelic/native-metrics": "^11.0.0",
    "@prisma/prisma-fmt-wasm": "^4.17.0-16.27eb2449f178cd9fe1a4b892d732cc4795f75085"
},

なんか optionalDependencies があるんですけど、 npm i newrelic だけじゃないの?ドキュメントに書いてあった?

調べよう(2回目)

ありましたよ、ドキュメント。 Node.jsのVM測定

New Relic Node.js エージェントの v2.0.0 以降、ネイティブモジュールはオプションの依存関係となり、自動的にインストールされるようになりました。

じゃぁインストールされんのかな?と思うじゃないですか。ダメです。

展開プラットフォームでネイティブ モジュールをコンパイルするには、 node-gypパッケージの手順に従います。ネイティブ Node.js モジュールをインストールするための前提条件は次のとおりです。 プラットフォーム 前提条件 Unix/Linux Python(v2.7推奨、v3.x.xは未サポート)、make、C/C++コンパイラ(GCCなど)

いやいや、 Python 必要なん? (node-gyp だから当然だけど)。 つまり自動インストールしようとした結果、インストールに必要なもの(今回でいうとgccとかPytnonとか)がインストールされてないので、自動インストール自体が失敗するということになります。

Node.jsエージェントのインストール という公式ドキュメントをみると

オプション:追加のNode.jsランタイムレベル統計情報を取得するため、@newrelic/native-metricsパッケージがインストールされていることを確認してください。

ってことで、まぁこれは必要なようです。

結局のところの deps は以下のようになりました。

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
# RUN apk add --no-cache libc6-compat
RUN apk update && \
  apk upgrade && \
  apk add --no-cache libc6-compat make gcc g++ python3
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi

RUN npm i -g newrelic
RUN npm i -g @newrelic/native-metrics

やってみる(3回目)

動いたー🎉

まとめ

以下、苦労したところ

  • ドキュメントが分散していてわかりずらい(最初から github でなく公式 Docs みておいた方が良かったかも)
  • Next.js の standalone モードとは驚くほど相性が悪い

前者は改善の余地ありそうだけど、後者は何ともならなそうですね。 今回は別の場所で入れて NODE_PATH するというハックを使いましたが、結局エージェントとWebアプリで依存関係の競合が起きたときに困ると言うことには違いないです。たとえば違うバージョン使っていたら?とかそれが原因で動かなかったら?ということは今後容易に起きそうです。 希望としてはエージェントは1ファイルにパッキングしておいて欲しいということですね。というか require module で動くんだから自分が必要なパッケージは固めておいて欲しいですよね。Node.js のアプリだったらみんながみんなフルセットの node_modules を使っていないことがあるのは Node.js 使っている人ならわかりそうなのになぁという気分です。

ちゃんと時間が取れて、良い感じの英文が書けたら issue 出そうかな。それも OSS への貢献ですね。 この記事で同じような境遇になった人が、解決の助けになったら、と思います。

PHPカンファレンス小田原2025に参加しました

この記事は PHPカンファレンス小田原2025 に参加したレポートです。

今年も月刊PHPカンファレンスなようですが、昨年末ぐらいから多忙のため通常のPHP勉強会にも出れない日々が続いておりました。 ようやく落ち着いてきてイベントにも出れるようになってきたので、久々のイベント参加です(というか、もう小田原ぐらいには落ち着いてないとダメだろうという前提でチケットを購入していた)。

小田原は新宿駅から乗り換えなしで行けるし、都民にとってはPHPカンファレンス東京と並んで行きやすいカンファレンスです。

なんか去年もそうだった記憶があるけど、ロマンスカーあんまり乗らないので事前に購入するという発想がなかった。ロマンスカーなら70分、快速急行だと100分ぐらいなのでギリ間に合うかなという感じ。

はい。

受付してノベルティをGETして会場へ急足。小田原のノベルティTシャツが今年もステキだった(写真撮り忘れた)。まだ着てないけど昨年のもお気に入りなんで、今年のも何度も切る場面がありそう。

参加したセッション

AM

午前中はメイン会場の かま

  • キーノート OSSコントリビュートをphp-srcメンテナの立場から語る
  • PHP 8.x 時代のクラス設計
  • PHPと旅する OSI 7階層
  • PHPバージョンアップから始めるOSSコントリビュート
  • 古き良きLaravelのシステムは関数型スタイルでリファクタできるのか

OSSコントリビュートは普段から心がけているので、自分が使うライブラリだったり、自分が作るライブラリだったり、いろいろあるけど貢献する意識づけとかはチームメンバーにも植え付けていきたいし、カンファレンスとかにも出て刺激をうけてほしいですね。会場アンケートでコントリビュートしたことある人、というアンケートに、こういうところに来る人なんでバイアスかかってますけどね、というコメントがありましたけど、確かにーと思うところ。

PHPは個人サービスを作る時のバックエンドで長らく使っていたけど、最近はNode.jsばかりなので昔のサービスのメンテぐらいでしか書いてないけど、クラス設計の話を聞くと昔から他の言語のいいところを取り入れて進化してきたので、クラスの話を聞くとJavaっぽいと思うのは自然な感じかな。いろいろ最新状況が知れてよかった。

OSI7階層の話は、別のカンファレンスでそれぞれの層の話を聞いたりしてるので、全体の流れの話で聞けるのもよかった。僕はそういう突き詰める系はあんまりやらないけど、自分の好きな開発ができるときって楽しいですよね。僕だと個人Webサービス作ってる時が楽しいです。

リファクタリングは、どのタイミングでやるかは非常に重要だけど、聞いた話レベルでやるのは大変そうだなーと思った。改善は一気にできないことが多いので、少しでもやりやすい方法で進められると良いですね。

ランチ

ランチではランチコラボで、地元のお店でプチサービスが受けられるところが準備されていたり、ぼっち飯にならないようにランチマッチング企画が準備されていたり、すごい充実してました。 とはいえ、僕はタイミングを逃して1人で美味しそうな料理とお水があるお店に吸い込まれていきました。 小田原の路地にあるお店、どこも入り口が広くて開放していたので、様子が伺えてよかったです。

PM

午後は あじ

  • 恣意性から考える、変更に強いモデルの作り方
  • タイムゾーンの奥地は思ったよりも闇深いかもしれない

最後は かま に戻って

  • New RelicのAPMを活用したECサービスにおけるメール遅延解消の舞台裏
  • スポンサーエレベータピッチ
  • LT
  • ぺちおだ大合戦

恣意性はふむふむ、そうだなーと思うところがあったり、自分はこうだなーと思うところがあったりして、考え方の整理ができてよかったです。

タイムゾーンはちょっと思ってた内容と違ってたけど、まぁUTCにしとけってとことはそうですね!

アプリの計測は大事で、最近はAWS使うことが多いのでX-Rayを使っていることが多いけど、何を使うにせよデータがないと困りますしね。最近業務でX-Ray使っていて新しい知見もあったので、ブログにも書いていこうと思います。

ぺちおだ大合戦、最初はどんなことが起きるんだろう?と思ったけど、終わってみてこれはすごい企画だなーというのと、運営の準備大変だっただろうな、お疲れ様でした。とても楽しかったです!という一言です。とにかくすごい。

懇親会

万葉の湯で豪華な懇親会がありました。畳部屋での立食形式もあんまり体験したことない感じだった。こちらも写真は撮ってませんでした…(楽しかったという記憶は間違いない)。 最終のロマンスカーの時間があるので、少し早く離脱して無事帰宅できました。

全体的な感想

昨年も参加して、今年もいろいろ考えられてて企画力がすごいですよね。

来年のことについてはコメントしませんが、これだけの企画をやると燃え尽き症候群とかになっても不思議ではないと思うので、ゆっくり休んで他のカンファレンスに参加して充電?してかな。

参加した方もためになったし、元気がもらえたし、楽しかったし、とても充実した1日でした。

Next.js で作ったアプリケーションを AppRunner にデプロイする

こちらの記事は AppRunner へのデプロイは cdk でサクッとできるのか? の続編となります。 前編を読まないとわからない内容ではないですが、もし良ければ事前に確認してください。

まず前編でも触れてますが、アプリケーションのリポジトリ構成は以下のようになっています。

  • Next.js のアプリケーションリポジトリ
  • AWSのリソースを管理するインフラリポジトリ

アプリのリポジトリでは、ECR へのデプロイまでやってます。 インフラのリポジトリで、AppRunner など AWS リソースを CDK で構築しています。

AppRunner で Next.js アプリケーションを動かすには

Next.js を standalone モードでビルドして、Docker コンテナで起動する。これだけで ok です。

ECR に Next.js の standalone モードビルドしたコンテナイメージを push する

まずは Next.js のアプケーションリポジトリの CI/CD で ECR に Docker イメージを push します。 アプリケーションリポジトリ側にも CDK を入れてあるので、以下のようなコードで ECR にデプロイしています。 タグは package.jsonversion から入手します。

import * as imagedeploy from 'cdk-docker-image-deployment'
import * as ecr from 'aws-cdk-lib/aws-ecr'

export class DeployStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    const projectRoot = path.join(__dirname, '../..')
    const { version } = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json')).toString())
    const repository = ecr.Repository.fromRepositoryName(this, 'webapp-ect', 'webapp')
    new imagedeploy.DockerImageDeployment(this, 'DockerImageDeployment', {
      source: imagedeploy.Source.directory(projectRoot),
      destination: imagedeploy.Destination.ecr(repository, {
        tag: version,
      }),
    })

Dockerfile は Next.js の公式サンプルWith Docker を参考に(というかほぼそのまま流用)すれば大丈夫です。 ベースイメージの Node.js バージョンが古かったりするので、そこは自分たちが使うバージョンに変更しておきましょう。

AppRunner で ECR からデプロイする

こちらは前編でも触れた @aws-cdk/aws-apprunner-alpha が使えるので簡単にデプロイできます。 以下のような感じで書けば良いでしょう。ヘルスチェックを何でやるかは、いろいろだと思いますが、ここではいったん favicon にしています。 CDK で作成した ECR のリポジトリと、デプロイ対象のアプリケーションバージョンはコンストラクタの引数で渡せるようにしています。

import { Service, Source } from '@aws-cdk/aws-apprunner-alpha'

export class WebAppConstruct extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: WebAppConstructProps) {
    super(scope, id, props)

    const service = new Service(this, 'WebAppService', {
      source: Source.fromEcr({
        imageConfiguration: { port: 3000 },
        repository: props.ecrRepository,
        tagOrDigest: props.webAppVersion,
      }),
      serviceName: 'webapp-service',
      autoDeploymentsEnabled: true,
      healthCheck: HealthCheck.http({
        healthyThreshold: 2,
        interval: Duration.seconds(10),
        path: '/favicon.ico',
        timeout: Duration.seconds(10),
        unhealthyThreshold: 10,
      }),
    })

コラム: ヘルスチェックについて、いろいろと参考になった記事

実はヘルスチェックはちょっといろいろあって実際も favicon にしたんですけど、そのときに参考になった記事があるので、載せておきます

デプロイできたので動かしてみるが動かない

Error: listen EADDRNOTAVAIL: address not available 10.0.1.2:3000

何か動きません。

あれ、Dockerfile に HOSTNAME=0.0.0.0 入ってるのに何でだろう? ローカルで build したイメージ動かしたときは大丈夫だったんだけど?と思ったら、1つ罠があります。

こちらの記事がとても参考になりました。 AWS App RunnerでNext.jsのstandaloneモードを動かす時のTips(ないしは失敗談)

App Runnerの環境では環境変数HOSTNAMEに対して、暗黙的にアタッチされているENIのprivate DNSが指定されるようです。

なんですって? AppRunner が環境変数にセットしてくるの??

だから 10.0.1.2:3000 みたいな ENI の private アドレスになるんですね。Dockerfile では

ENV HOSTNAME="0.0.0.0"
CMD ["node",  "server.js"]

のように指定されていても、コンテナ起動時に HOSTNAME を指定されるので環境変数が上書きされてセットされます。

CDK で HOSTNAME を設定する

ということで、AppRunner のサービスを作るときに環境変数 HOSTNAME を指定してあげます。

    const service = new Service(this, 'WebAppService', {
      source: Source.fromEcr({
        imageConfiguration: {
            port: 3000,
            environmentVariables: {
                HOSTNAME: '0.0.0.0',
            }
        },

これでデプロイしたら無事起動しました。👏👏

少しでも AppRunner で Next.js アプリを動かす人の役にたてばと思います。

AppRunner へのデプロイは cdk でサクッとできるのか?

AWS App Runner は、ソースコードまたはコンテナイメージから AWS クラウドのスケーラブルで安全なウェブアプリケーションに直接デプロイするための、高速でシンプル、かつ費用対効果の高い方法を提供する AWS サービスです。

公式ドキュメント に書かれています。

ソースコードからデプロイする場合は

  • GitHub
  • BitBucket

といったところのクラウドリポジトリを使っていれば簡単に連携して自動デプロイができます。

一方、仕事でオンプレのソースコードリポジトリ、たとえば GitHub Enterprise とか BitBucket Server とか、GitLabs とかをパブリッククラウドでなく使っている場合はソースコード連携できないので、ECR にイメージをデプロイして AppRunner と連携することになります。 本ブログは、この方法について、ネット上で簡単にできそうに書いてある記事をやってみたら、実際はそんなことなかったということについて記録するものです。

CDK で AppRunner + ECR でデプロイする

cdk apprunner DockerImageDeployment みたいな検索条件でググると、まぁいっぱい出てきます。

ここで DockerImageDeployment というのは、Dockerfile をビルドして ECR に push までしてくれる CDK のライブラリです。 で、その ECR を AppRunner に関連づけてというのが流れです。

ちなみに DockerImageAsset というのもあって、そちらの記事も多く見受けられます。こちらはあらかじめ ECR を作っておかなくてもいい感じに作ってくれるものですが、[AWS CDK] コンテナイメージもまとめてデプロイ!?DockerImageAssetの動作確認をしてみた という記事のとおりお試しで使う分には良いと思いますが、ちゃんと管理して使いたい場合は DockerImageDeployment を使った方が良いでしょう。

DockerImageDeployment を使って ECR にデプロイする

DockerImageDeployment の公式GitHubリポジトリ にある例どおり簡単に利用できます。

import * as ecr from 'aws-cdk-lib/aws-ecr';
import * as imagedeploy from 'cdk-docker-image-deployment';

const repo = ecr.Repository.fromRepositoryName(this, 'MyRepository', 'myrepository');

new imagedeploy.DockerImageDeployment(this, 'ExampleImageDeploymentWithTag', {
  source: imagedeploy.Source.directory('path/to/directory'),
  destination: imagedeploy.Destination.ecr(repo, { 
    tag: 'myspecialtag',
  }),
});

AppRunner と連携でデプロイする

@aws-cdk/aws-apprunner-alpha というまだα版ですが、CDK のコンストラクタがあるので、これを利用します。

import * as ecr from 'aws-cdk-lib/aws-ecr';

new apprunner.Service(this, 'Service', {
  source: apprunner.Source.fromEcr({
    imageConfiguration: { port: 80 },
    repository: ecr.Repository.fromRepositoryName(this, 'NginxRepository', 'nginx'),
    tagOrDigest: 'latest',
  }),
});

あとは CDK でいい感じにつなぎこんで、みたいな感じです。

やってみたがエラーになる

はい、エラーになりました。

The deployment will wait until the CodeBuild Project completes successfully before finishing.

というメッセージが出て失敗します。 メッセージどおり受け取ると、ECR のデプロイが終わってないので AppRunner にデプロイできないということです。

どうやって解決したか

実はアプリケーションのソースコードリポジトリと、AWSのリソース構成をデプロイするインフラリポジトリは分けていたので、アプリケーションコード側の CI/CD で DockerImageDeployment を使って ECR までデプロイ。 ECR までデプロイされている状況で、インフラリポジトリ側の CI/CD で ECR と AppRunner の関連付けをやるようにしました。

では最初はなんで両方を一緒にやっていたかというと、アプリケーションが外部サービスに連携しているため、開発環境ではモックサーバーを使っているのですが、それは Dockerfile 1つだけなんでそのファイルをインフラリポジトリ側において AppRunner にデプロイしようとしていたという感じでした。

他の解決策としては、カスタムリソースを使って ECR へのデプロイを待ち合わせてデプロイするという方法があります。モノレポなどを使っているときにアプリケーションとインフラを同時にデプロイしたいときなどは有効な方法だと思います。 カスタムリソースも Lambda を作らないといけないというわけではなく、 AWS の API を実行する程度なら Lambda が不要なので、そういった選択肢も検討できます。

参考記事: [AWS CDK] APIを呼び出すだけのカスタムリソースならLambda関数は不要な件

さいごに

AppRunner を cdk を使ってデプロイしたい、というときに参考になれば幸いです。 @aws-cdk/aws-apprunner-alpha がαじゃなくなるときには、もう少し便利に(ちゃんと待ち合わせてくれるみたいな)ことができるようになるのかもしれないので期待はしたいですね。

ちなみにモックサーバーは Mockoon を使ってます。とても便利で助かる。

PHP カンファレンス福岡2024に参加した

PHP カンファレンス福岡2024に参加しました。

2019年以来の PHP カンファレンス福岡。 そのときの記事がPHPカンファレンス福岡2019で、 標準インターフェースを使ったアプリケーション開発について発表してきましたです。

昨年はチケットを購入できず、先に予約していたフライトやホテルをキャンセルするという形になってしまったので、今年はちゃんとチケット購入してから、フライトとホテルを予約しました。昨年の反省が活かされている。 昨年の盛り上がりは X で確認していて、うらやましーと思ってました。そこから今年の月刊 PHP con が始まったと言っても過言ではないわけで、とても楽しみにしていました。

ちなみにプロポーザルはブログ記事にもしたGAE gen1 で動いている PHP5.5 で作った個人開発サービスを gen2 PHP8.2 へ移行した1年記APPSYNC_JS (AppSync JavaScript) で始める GraphQL API サーバーについて出したのですが、どちらも落選しました。 プロポーザルの倍率がやばすぎる(僕が普段の仕事 PHP じゃないので、旬な話題じゃないというのは否定できない事実ですがw)。

2019年が3年ぶり2回目だったので、今回は5年ぶり3回目ということになります。

前日入り

今回も前日入りしましたが、いきなり飛行機が遅延するというトラブルに。

この時点では 9:00 発が 9:40 になっただけだったけど、さらに 15分遅延となって 9:55 発に。 梅雨時期だし雨の影響もあるのでしかたがないですね。前日入りでよかったとポジティブに捉えましょう。

福岡に到着したら WeWork 大名へ。永和システムマネジメントでは東京支社がWeWork京橋内になったため、今回のように福岡に前日入りしてもWeWork拠点があれば作業できるのでとても便利。夕方からは袋詰めボランティアに申し込んでいたので、それまで作業します。

お昼はWeWork近くにあったウェストへ。

夕方ぐらいになったらWeWorkに知っている人たちが続々来て??ってなったんですが【非公式】PHPカンファレンス福岡2024・前日Meetup があったようです。気が付いてなかった….

そして袋詰めをやってきました。

そのあとは特に予定もなかったので、エールズへ。

野生のPHPerにも出会えたり、帰ろうかなーと思ったら店長から市川さん来るよ、って教えてもらったのでビールを追加して合流。 そのあとは Rummy 行って美味しいラムをいただいて、締めにやまちゃんでラーメンとビールを(3時ちょいに寝ました)。

当日

ちゃんと朝起きれて会場へ移動していたのですが、2日続けて朝にトラブルが…

100円均一で売ってるこの手の定期入れを使ってたんですが、初めて中身だけ落ちました。

祇園駅で駅員さんに天神駅へ連絡してもらって確認したら、それっぽいのがあるということでUターンして無事戻ってきました。 日本でよかった。改札通過してすぐポケットに入れた(いつもそう)ので、改札近くに落ちたのではないかと思います。 ギリギリ開始時間には間に合いました。

今回は午前中はメイン会場でセッションに参加してました。PHP養分がたくさん補充されました。

お昼は福岡の人と食べたいなーと思って、@nojimageさんに声をかけてご一緒させてもらいました。

午後はアンカンファレンス会場、スポンサーブース、廊下で交流してました。

16:00からはアンカンファレンス会場で、会社で今月2回Webアクセシビリティのワークショップをやったのを発表しました。

専門家じゃなくても良い教材があるので「みんなで勉強会てきにやってみると良いよ」といったメッセージが伝わったら良いなと思っています。

そのあとは懇親会(当日チケットあって嬉しかった)→ 非公式2次会 → やまちゃん の流れでした。 初めましての方、お久しぶりの方とたくさん話せました。楽しかった!

後日

帰京までの時間は6/23(日)「(非公式)PHP Conference Fukuoka After Hack!!」に参加して、このブログ記事を書いています。

2019年の記事の最後は

PHPカンファレンス福岡、来年も参加できると良いなー。

で終えていました。 しかし翌年それが当たり前の光景でないことがわかったのです。当時はそんなことになると思っていなかったですよね。 もちろんそういったことだけでなく、当たり前にカンファレンスがある訳でなく、多くの人の努力によって開催されているわけで感謝です。

あとはアンケートとフィードバックを入れてから帰ります。そしてまた参加できるように願っています。