Java Codeシリーズを使ったCI/CD


はじめに

転職活動の際にポートフォリオとして、Javaを使用したアプリケーションを作成しました。
GitHubへソースコードをプッシュすると、AWS上のEC2へデプロイされるように環境を作成した際のメモを残そうと思います。

Codeシリーズの作成方法などは他の記事を参照して頂き、本記事では

・デプロイされるときに、自動的に本番環境の設定ファイルでデプロイされるようにしたい!!

となったときに、各種設定ファイル(Mavenのpom.xmlや、CodeBuildのbuildspec.yml、CodeDeployのappspec.yml)の書き方についてざっくり触れていきたいと思います。

どなたかの参考になれば幸いです。

※環境作成から本記事の執筆に時間が空いてしまったため、思い出しながら記載しています。誤りがあってもあしからず・・・

処理の流れ

GitHubへコードをプッシュ→CodePipelineが起動→CodeBuildでソースコードのビルド(&テスト)→CodeDeployでEC2へデプロイ

イメージ図

やった事

作成するアプリは、Mavenプロジェクトとして作成しました。

ディレクトリ構成は下記の通りです。

アプリケーションディレクトリ
 |-- pom.xml
 |-- buildspec.yml                               ←CodeBuildで使用
 |-- appspec.yml                                 ←CodeDeployで使用
 |-- src
       |-- main
       |     |-- java
       |           |-- modelとかcontroller
       |     |-- config
       |           |-- honban                    ←本番用の設定ファイルを配置
       |                 `-- context.xml とか
       |           |-- local                     ←ローカル用の設定ファイルを配置
       |                 `-- context.xml とか
       |-- test
             |-- java
                   |-- modelテストコードとか


ローカル環境と本番環境では、DB接続パラメータが異なるため、ビルド時のパラメータでローカルか本番かを分けて、ビルド出来るようにpom.xmlを作成します。

pom.xml(抜粋)
  <build>
    <finalName>calendar</finalName>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.1</version>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.2.2</version>
            <configuration>
                <webResources>
                    <resource>
                        <directory>${contextxml.path}</directory>  ←ここでcontext.xmlのパスを変えれるようにしている。実際のパスは下記のprofileの部分で指定
                        <targetPath>META-INF</targetPath>
                        <filtering>true</filtering>
                        <includes>
                            <include>context.xml</include>
                        </includes>
                    </resource>
                    <resorce>
                        <directory>${loggingproperties.path}</directory>
                        <filtering>true</filtering>
                        <includes>
                            <include>logging.properties</include>
                        </includes>
                    </resorce>
                </webResources>
            </configuration>
        </plugin>
    </plugins>
  </build>

  <profiles>
    <profile>
        <id>local</id>  ←ビルド時にlocalを引数で渡すと、このprofileセクションの値が使用される
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <contextxml.path>src/main/config/local</contextxml.path>
            <loggingproperties.path>src/main/config/local</loggingproperties.path>
        </properties>
    </profile>
    <profile>
        <id>honban</id>  ←ビルド時にhonbanを引数で渡すと、このprofileセクションの値が使用される
        <properties>
            <contextxml.path>src/main/config/honban</contextxml.path>
            <loggingproperties.path>src/main/config/honban</loggingproperties.path>
        </properties>
    </profile>
  </profiles>

CodeBuildでビルド動作を定義するbuildspec.ymlは下記のように作成しました。

buildspec.yml
version: 0.2

env:
  variables:
    S3_BUILD_OUTPUT_BUCKET: "calendardeploybucket"

phases:
  install:
    runtime-versions:
      java: corretto8
    commands:
      # treeコマンドを使いたいのでインストール
      - yum install -y tree

  pre_build:
    commands:
      - echo Nothing to do in the pre_build phase...
      - mvn clean
  build:
    commands:
      - echo Build started on `date`
      # maven実行(honban用でパッケージ。今回はテストスキップ。。)
      - mvn package -P honban -DskipTests=true

      # ソース,java,mavenのバージョンを出力
      - echo "--------------------------------------------------" >> version.txt
      - echo "SourceVersion:"$CODEBUILD_RESOLVED_SOURCE_VERSION >> version.txt
      - java -version 2>> version.txt
      - mvn -version >>version.txt
      - echo "--------------------------------------------------" >> version.txt

  post_build:
    commands:
      - echo Build completed on `date`

      # treeコマンドで確認
      - tree >>tree.txt
      - aws s3 cp tree.txt s3://$S3_BUILD_OUTPUT_BUCKET
      # version.txtの移動
      - aws s3 cp version.txt s3://$S3_BUILD_OUTPUT_BUCKET
      # warファイルとappspec.xmlを一つのZIPファイルに固める
      - zip -r ./calendar.zip ./target/calendar.war ./appspec.yml
      # S3にzipファイルをアップロード
      # - aws s3 cp ./calendar.zip s3://$S3_BUILD_OUTPUT_BUCKET

artifacts:
  files:
    - target/calendar.war
    - appspec.yml
  discard-paths: no

諸々、ほかのサイトを参考にした箇所がありますが・・・
上記のbuildspec.ymlにおいて、大事なのは、ビルドコマンドとして、mvn package -P honban -DskipTests=true を実行しています。
-Pオプションでhonbanを指定することで、pom.xmlのprofileで指定したパスのファイルが使用されます。
テストは通常であれば、スキップせずに実行してください。。

また、CodeBuildでビルドしたwarファイルはS3に格納しますが、その際に、後続のCodeDeployが使用するappspec.ymlも一緒にzipファイルに入れています。
zipで固める際に、CodeBuildが元のファイルを見つけれるように、artifactsのセクションでmvnコマンドで作成されるwarファイルだけでなく、appspec.ymlも指定しています。

ここが一番つまづいた気がします。。

あとは、CodeDeployで使用するappspec.ymlですが、これはそのままwarファイルを配置するだけです。

appspec.yml
version: 0.0
os: linux
files:
  - source: target/calendar.war
    destination: /usr/share/tomcat/webapps/

これで、あとはCodeシリーズを作れば、いい感じにJavaアプリがデプロイされるはず!

どなたかの参考になれば・・・