CDK PipelinesでLambdaをデプロイする時にCodeBuildでdockerのエラーが出る(Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?)

2022.11.21

「CDK PipelinesのCodeBuild上で、cdk synthやDocker関係のエラーが出たらpipelines.CodePipelinedockerEnabledForSynthdockerEnabledForSelfMutationtrueになっていることを確認しよう」

# エラーメッセージ
[Container]Running command npx cdk synth
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
docker exited with status 1
[Container] Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: npx cdk synth. Reason: exit status 1

Using bundled file assets aws-cdk-lib.pipelines module · AWS CDK

事象

CDK PipelinesでLambdaのスタックをデプロイしようとしていました。 しかし、CDK Pipelines上のCodeBuildで以下のエラーがでます。(エラーメッセージは上記)

Lambdaスタックの単体でのデプロイは成功します。

エラー発生時のコード

bin/index.ts

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as codecommit from 'aws-cdk-lib/aws-codecommit';
import * as pipelines from 'aws-cdk-lib/pipelines';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as nodeLambda from 'aws-cdk-lib/aws-lambda-nodejs';
import * as path from 'path';

const app = new cdk.App();

class LambdaStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    new nodeLambda.NodejsFunction(this, 'NodejsFunction', {
      entry: path.join(__dirname, '../lambda/index.js'),
      handler: 'handler',
      runtime: lambda.Runtime.NODEJS_16_X,
      timeout: cdk.Duration.seconds(120),
    });
  }
}

class DeployStage extends cdk.Stage {
  constructor(scope: Construct, id: string, props: cdk.StageProps) {
    super(scope, id, props);
    new LambdaStack(this, 'LambdaStack', {});
  }
}

class PipelinesStack extends cdk.Stack {
  constructor(scope: Construct, id: string, porps?: cdk.StackProps) {
    super(scope, id);

    const repository = codecommit.Repository.fromRepositoryName(this, 'Repository', 'cdk-pipelines-sample');
    const source = pipelines.CodePipelineSource.codeCommit(repository, 'main');

    const pipeline = new pipelines.CodePipeline(this, 'Pipeline', {
      synth: new pipelines.ShellStep('Synth', {
        input: source,
        commands: ['npm ci', 'npm run build', 'npx cdk synth'],
      }),
    });
    pipeline.addStage(new DeployStage(this, 'Test', {}));
  }
}

new PipelinesStack(app, "CdkPipelineStack")

原因

Lambdaのコードをデプロイするために、スクリプト等を1つのZIPファイルにする(バンドル)の処理が実行されます。 その際に、Dockerが使用されます。

この処理をCodeBuild上で行うために、CodeBuild上でDockerを実行する必要があります。

しかし、CodeBuild上で特権モードが有効(デフォルト無効)になっていない場合Dockerを起動しようとするとエラーになります。

Error: "Cannot connect to the Docker daemon" when running a build (ビルドの実行時に「Docker デーモンに接続できません」) AWS CodeBuild のトラブルシューティング - AWS CodeBuild

CDKPipelinesで作成したCodeBuildを見てみると、特権モードが無効になっています。

対策

CodeBuildの特権モードを有効になるように、CDKPipelineのプロパティにdockerEnabledForSynth: trueを追加します。

CDKのドキュメント上では以下に、記載があります。

Using bundled file assets aws-cdk-lib.pipelines module · AWS CDK

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as codecommit from 'aws-cdk-lib/aws-codecommit';
import * as pipelines from 'aws-cdk-lib/pipelines';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as nodeLambda from 'aws-cdk-lib/aws-lambda-nodejs';
import * as path from 'path';

const app = new cdk.App();

class LambdaStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    new nodeLambda.NodejsFunction(this, 'NodejsFunction', {
      entry: path.join(__dirname, '../lambda/index.js'),
      handler: 'handler',
      runtime: lambda.Runtime.NODEJS_16_X,
      timeout: cdk.Duration.seconds(120),
    });
  }
}

class DeployStage extends cdk.Stage {
  constructor(scope: Construct, id: string, props: cdk.StageProps) {
    super(scope, id, props);
    new LambdaStack(this, 'LambdaStack', {});
  }
}

class PipelinesStack extends cdk.Stack {
  constructor(scope: Construct, id: string, porps?: cdk.StackProps) {
    super(scope, id);

    const repository = codecommit.Repository.fromRepositoryName(this, 'Repository', 'cdk-pipelines-sample');
    const source = pipelines.CodePipelineSource.codeCommit(repository, 'main');

    const pipeline = new pipelines.CodePipeline(this, 'Pipeline', {
      synth: new pipelines.ShellStep('Synth', {
        input: source,
        commands: ['npm ci', 'npm run build', 'npx cdk synth'],
      }),
      dockerEnabledForSynth: true
    });
    pipeline.addStage(new DeployStage(this, 'Test', {}));
  }
}

new PipelinesStack(app, "CdkPipelineStack")

ちなみに、CDK Pipelines上でDocker image Assetsを使う場合は、dockerEnabledForSelfMutation: trueも追加する必要があります。

おわりに

CDK PipelinesでLambdaをデプロイする際に出たエラーに関してでした。

cdk.devのSlackでちょうど同じエラー出ている人を見つけられたので、Google検索で見つからない場合はcdk.devのSlack内検索してみるのもいいかもしれません。

以上、AWS事業本部の佐藤(@chari7311)でした。