SAMを使用せずCodePipeline内でLambdaコードの更新を反映させる手段

CloudFormationでIaCを構成しているとき、テンプレートの更新は反映されても、Lambdaのコードの更新が反映されない場合があります。
SAMを使用せず、以下のようなLambdaのテンプレートでデプロイしようとした時に発生しました。
```yaml:lambda.yaml
  TestPythonCode: 
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: TestPythonCode
      Code: 
        S3Bucket: !Ref RootBucket
        S3Key: 'TestPythonCode.zip'
      Role: 'arn:aws:iam::${AWS::AccountId}:role/lambdaExecusionRole'
      Handler: fileName.lambda_handler'
      Runtime: python3.12
```
この場合、S3Keyの値に更新がないと、CloudFormationの更新でLambdaのデプロイが反映されません。
変更セットに値の変更がないため、デプロイが実行されないようです。

## 解決策
### CodeBuild内でTimeStampを生成して、LambdaのZipファイル名につける。
S3のZip名にタイムスタンプを組み込むことで、CloudFormation内で毎回Lambda.zipファイルのデプロイが行われるようになります。

## 記載例

### タイムスタンプ作成シェル
``` shell: timestamp.sh
#!/bin/bash

# 変数に格納
timestamp=$(date +"%Y%m%d%H%M%S")
echo $timestamp
```

### LambdaをZip化するCodeBuildのアクション
```yaml: BuildSpec.yaml
          version: 0.2
          # ここでのちのアクションに受け渡す環境変数を作成
          env:
            exported-variables:
              - TIMESTAMP_LAMBDA
          phases:
            install:
              runtime-versions:
                python: 3.11
              command:
                - echo install
                - pip install --upgrade pip
                - pip install --upgrade --user awscli
                - aws --version
            pre_build:
              commands:
                - echo pre_build
            build:
              commands:
                - echo "CloudFormation Build"
            post_build:
              commands:
                - echo "CloudFormation template S3 push"
                - pwd
                - cd ./deploy/template/lambda/src
                - export TIMESTAMP_LAMBDA=$(sh ./timestamp.sh) # 環境変数にタイムスタンプを指定
                - echo $TIMESTAMP_LAMBDA
                - sh ./build.sh "$TIMESTAMP_LAMBDA"
                - cd ../../../../../
                - pwd
                - aws s3 cp ./02_deploy/$EnvironmentType s3://deploy/ --recursive --exclude "*" --include "*.yaml" --include "*.zip"
```


### CodePipelineのテンプレート
```yaml: codepipeline.yaml
Resources:
  # Deploy Pipeline
  ppline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      # ~パイプラインの設定省略~ 
      
      Stages:
      # 変更セット作成ステージ
      - Name: ChangeSetCreateStage
        Actions:
          - Name: ChangeSetReplaceAction
            ActionTypeId:
              Category: Deploy
              Owner: AWS
              Version: 1
              Provider: CloudFormation
            InputArtifacts:
              - Name: SourceZip
            Configuration:
              ChangeSetName: Hoge
              ActionMode: CHANGE_SET_REPLACE
              StackName: Hoge
              Capabilities: CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND
              TemplatePath: "TemplateFilePath"
              RoleArn: "RoleArn"
            RunOrder: 1
            
    # 変更セットデプロイステージ
      - Name: Deploy
        Actions:
          - Name: DeployRoot1
            ActionTypeId:
              Category: Deploy
              Owner: AWS
              Provider: CloudFormation
              Version: 1
            Configuration:
              ActionMode: CHANGE_SET_EXECUTE
              RoleArn: "RoleArn"
              StackName: Hoge
              ChangeSetName: Hoge
              # CodeBuild内で作成したタイムスタンプを指定
              ParameterOverrides: !Sub |
                {
                  "TimeStampLambda": "#{BuildVariables.TIMESTAMP_LAMBDA}"
                }
```
ParameterOberridesの項で、BuildSpec.yaml内でエクスポートした環境変数を指定してCloudFormationのパラメータに指定しています。

### Lambdaのテンプレート
```yaml: Lambda.yaml
  TestPythonCode: 
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: TestPythonCode
      Code: 
        S3Bucket: "TestBucketS3URI"
        # ポストフィックスにタイムスタンプをつける
        S3Key: 'TestPythonCode_${TimeStampLambda}.zip'
      Role: 'arn:aws:iam::${AWS::AccountId}:role/lambdaExecusionRole'
      Handler: fileName.lambda_handler'
      Runtime: python3.12
```
S3のZip名にタイムスタンプを組み込むことで、CloudFormation内で毎回Lambda.zipファイルのデプロイが行われるようになります。


## 最後に
今回は既存のソースコードを修正、かつSAMを使わないという縛りだったため、このようになりましたが、
新規開発の場合はSAMを使用してcloudformation --packageをした方が良いかと思います。