Edited at

弊社ECサイト用APIサーバのCI/CD環境今昔

ハンズラボ Advent Calendar 2018 16日目の記事です。

ECサイト担当になって早3年を過ぎ、その間にCI/CD環境を継続して改善し続けてきました。

この度ようやくParavirtualなインスタンスで動作していたJenkinsサーバを停止し、一段落したこともあり、来し方を振り返ってみます。


APIサーバのCI/CD環境今昔


チーム参加時点(2015/09)

  Gitリポジトリ: Atlassian Stash

- 今はBitbucketに吸収されてしまいました
CI: Jenkins
- Antから以下を実行
- PHP Lint(php -l)
- PHP Mess Detector
- PHP Code Sniffer
- PHPUnit
CD: Jenkins
- eb deployコマンドをbashスクリプトで実行


当時を振り返って


  • Atlassian Stashにログインできるメンバーが社内に数名しかいなかった・・・

  • AntジョブがXMLで書いてありメンテナンスできない


Gitリポジトリ移行(2015/12)

+ Gitリポジトリ: Backlog


当時を振り返って


  • BacklogのGitリポジトリでプルリクエスト機能が追加されたこともありBacklogへ移行


    • Githubも社内で利用開始していたが、Backlogは当時からエンタープライズプランで追加費用がなかった




決済APIサーバ分離(2016/02)

+ CI: Jenkins

+ - Antをやめて、composerスクリプトでの実行に修正
+ CD: Jenkins
+ - bashスクリプトで待機系を判定し、待機系へ`eb deploy`


当時を振り返って


  • ステージング環境と本番環境のAWSアカウントの分離にチャレンジした


    • ステージング環境にdeployしたCommitと本番環境に差異を発生させたくなかったため、ステージング環境deploy時に本番環境の待機系へもdeploy

    • 本番環境のCNAMEから待機系を判断



  • Jenkinsユーザが実行するジョブをvisudoで追加するのを忘れていて動かない


決済APIサーバのCI/CD環境移行(2018/06)

+ Gitリポジトリ: CodeCommit

+ CI: CodePipeline + CodeBuild
+ - PHP Parallel Lint に変更
+ - CodeBuildのDockerイメージでhttpdを起動してAPIのテストを実行
+ CD: CodeBuild
+ - CodeBuildからeb deployコマンドをbashスクリプトで実行


当時を振り返って


  • Meltdown/Spectre以降、Paravirtualインスタンスへのメンテナンス頻度が上がり、Jenkins廃止の機運が高まった

  • CodePipelineはBacklogのGitリポジトリからhookできない・・・


    • CodeCommitの使い心地を試してみる



  • CodeBuildでのCIでハマる


    • 今はローカル実行できていいですよね・・・



  • CodePipelineからElastic BeanstalkへdeployしたいがAWSアカウントをまたいでのdeployは素直には無理


    • 仕方なくCodeBuildからeb deployする




APIサーバのCI/CD環境移行(2018/11)

+ Gitリポジトリ: Github

+ CD: CodePipeline + Lambda
+ - CodePipelineからElastic Beanstalkの待機系へdeploy
+ - 手動承認したらLambdaでswap
+ - swap完了後に未deploy側へdeploy
+ - deploy完了したら再swap


当時を振り返って


  • CodeCommit辛い


    • プルリクエストしたらAWSのマネジメントコンソール開くの???

    • httpsにしてもsshにしても辛い

    • 諦めてGithubに移行



  • CodeBuildでのPHPMD/PHPCSで落ちる


    • Jenkinsサーバでは通るが、新環境では落ちる・・・

    • 仕方なく、通るまでチェックルールからルールを一つずつ削除する。辛い。



  • ステージング環境と本番環境のAWSアカウントを分離


    • featureブランチからdevelopブランチにマージ→ステージング環境にdeploy

    • developブランチからmasterブランチにマージ→本番環境にdeploy



  • CodePipelineからのLambda呼び出しでハマる


    • LambdaからCodePipelineへ「ジョブが完了した」と通知する必要がありました



import boto3

import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

SOURCE_EB = os.environ['source_eb']
DEST_EB = os.environ['dist_eb']

def lambda_handler(event, context):
logger.info(event)

try:
beanstalk = boto3.client('elasticbeanstalk')
response = beanstalk.swap_environment_cnames(
SourceEnvironmentName = SOURCE_EB,
DestinationEnvironmentName = DEST_EB,
)

logger.info(response)

except Exception as e:
logger.error(e)
raise e

try:
codepipeline = boto3.client('codepipeline')
jobid = event['CodePipeline.job']['id']
response = codepipeline.put_job_success_result(
jobId=jobid,
)

logger.info(response)

except Exception as e:
logger.error(e)
raise e


今後

Elastic BeanstalkへのAmazon Linux2の公式対応待ちです。

その際には決済APIサーバのCI/CD方式をAPIサーバに合わせる予定です。

ECS + Fargate環境にも挑戦したいです。

今後も改善は続きます。


参考資料

ハンズラボ Advent Calendar 2018 明日17日目は@sr-mtmtです!