😊

Dagger Node.js SDKを使ってNuxt3をEC2にデプロイ

2023/08/04に公開

前提

  • SSMでEC2にログインできること

Daggerとは?

Dagger is a programmable CI/CD engine that runs your pipelines in containers.

(公式から引用)
https://docs.dagger.io/

CI/CDを好きな言語で書いて、コンテナで実行できるということだと思います。

各バージョン

$ node -v
v18.17.0

package.json
// ...
    "@dagger.io/dagger": "^0.6.4",
// ...

実装

Nuxt3アプリのビルド -> デプロイを実装しています。
環境変数は適宜設定してください。

公式のGet Startedをベースに必要な処理を追加しました。公式のドキュメントが充実しているので、だいたいはここを見ればわかります。
https://docs.dagger.io/sdk/nodejs/783645/get-started

build.mts
import Client, { connect } from '@dagger.io/dagger'

connect(
  async(client: Client) => {
    // ビルド
    const hostSrcDir = client.host().directory('.', { exclude: ['node_modules/'] })
    const builder = client.container().from('node:18.14-slim')
      .pipeline('build')
      .withDirectory('/src', hostSrcDir) // ソースをマウント
      .withWorkdir('/src')
      .withExec(['yarn', 'set', 'version', 'berry'])// yarnのバージョンを上げる なくても動くはず
      .withExec(['yarn', 'install'])
      .withExec(['yarn', 'build'])
    await builder.sync()

    // デプロイ用の変数を環境変数から取得
    const serverPrivateKey = process.env.SERVER_PRIVATE_KEY || ''
    const ec2User = process.env.EC2_USER || ''
    const ec2Server = process.env.EC2_SERVER || ''
    const awsAccessKeyId = client.setSecret('AWS_ACCESS_KEY_ID', process.env.AWS_ACCESS_KEY_ID || '')
    const awsSecretAccessKey = client.setSecret('AWS_SECRET_ACCESS_KEY', process.env.AWS_SECRET_ACCESS_KEY || '')
    const awsDefaultRegion = client.setSecret('AWS_DEFAULT_REGION', process.env.AWS_DEFAULT_REGION || '')

    // デプロイ
    // nodeのイメージである必要はないが、ビルド用コンテナと違うイメージを使うとダウンロードが発生するので揃えています
    const deployer = client.container().from('node:18.14-slim') 
      .pipeline('deploy')

      // ソースを配置
      .withDirectory('/src/.output', builder.directory('/src/.output'))
      .withFile('/src/pm2.config.js', client.host().file('pm2.config.js'))

      // 必要パッケージのインストール
      .withExec(['apt-get', 'update'])
      .withExec(['apt-get', '-y', 'install', 'curl', 'unzip', 'openssh-client', 'rsync'])

      // AWS CLIのインストール・設定
      .withExec(['curl', 'https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip', '-o', 'awscliv2.zip'])
      .withExec(['unzip', 'awscliv2.zip'])
      .withExec(['./aws/install'])
      .withSecretVariable('AWS_ACCESS_KEY_ID', awsAccessKeyId)
      .withSecretVariable('AWS_SECRET_ACCESS_KEY', awsSecretAccessKey)
      .withSecretVariable('AWS_DEFAULT_REGION', awsDefaultRegion)

      // AWS CLIのSession Managerプラグインのインストール
      .withExec(['curl', 'https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb', '-o', 'session-manager-plugin.deb'])
      .withExec(['dpkg', '-i', 'session-manager-plugin.deb'])

      // SSH設定追加
      // ※ssh -i で秘密鍵を指定する方法だと動かなかったので、鍵のパスをssh_configに記述しています
      .withNewFile('/etc/ssh/ssh_config', { contents: 'host i-*\n\tProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters \'portNumber=%p\'"\n\tStrictHostKeyChecking no\n\tIdentityFile /tmp/private.key' })
      .withNewFile('/tmp/private.key', {
        contents: serverPrivateKey,
        permissions: 0o0600
      })

    // デプロイ
    await deployer
      // ソースを更新
      .withExec(['rsync', '-ae', 'ssh', '/src/', `${ec2User}@${ec2Server}:app_dir/`])

      // pm2サーバーを起動
      .withExec(['ssh', `${ec2User}@${ec2Server}`, 'pm2', 'restart', "'app_name'"])
      .sync()
  },
  { LogOutput: process.stderr }
)

実行

$ node --loader ts-node/esm ./build.mts

問題点

参考

https://docs.dagger.io/current/sdk/nodejs/reference/modules

Discussion