TravisCI + CodeDeployでデプロイする

TravisCI + CodeDeployのフロー

【High Level】
– Merge Pull Request on master
– Travis Builds project automatically / run tests
– Travis uploads zipped project up to S3
– Travis then tells AWS Code Deploy to deploy to EC2 instance

【Index】
1. Pre-Setup
2. Policy For Server
3. Policy For Travis CI
4. Creating Travis User in IAM
5. Role for EC2 Instance
6. Role for Code Deploy Application
7. Create EC2 Instance
8. Create EC2 Tag
9. Create S3 Bucket
10. Setup Code Deploy
11. Project Setup
12. Setting Up Travis User Credentials on Travis
13. Code Deploy Agent Setup

### 1. IAMでEC2のPolicy作成
Policies -> Create Policy
Name: CodeDeployDemo-EC2-Permissions
Description: CodeDeployDemo-EC2-Permissions

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

-> このポリシーによって、EC2がS3からデータを持ってこれる

### 2. IAMでTravisCI、CodeDeployの為のPolicy作成
1.TravisがS3にアップロード
Travis-Deploy-To-S3

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

2.CodeDeployがEC2にデプロイ
Travis-Code-Deploy-Policy
※AccIdHEREはAWSの数字のID
※NameOfTheCodeDeployApplicationNameHEREはCodeDeployのapplication name
※ServerRegionHEREはap-northeast-1

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "codedeploy:RegisterApplicationRevision",
                "codedeploy:GetApplicationRevision"
            ],
            "Resource": [
                "arn:aws:codedeploy:ServerRegionHERE:AccIdHERE:application:NameOfTheCodeDeployApplicationNameHERE"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "codedeploy:CreateDeployment",
                "codedeploy:GetDeployment"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "codedeploy:GetDeploymentConfig"
            ],
            "Resource": [
                "arn:aws:codedeploy:ServerRegionHERE:AccIdHERE:deploymentconfig:CodeDeployDefault.OneAtATime",
                "arn:aws:codedeploy:ServerRegionHERE:AccIdHERE:deploymentconfig:CodeDeployDefault.HalfAtATime",
                "arn:aws:codedeploy:ServerRegionHERE:AccIdHERE:deploymentconfig:CodeDeployDefault.AllAtOnce"
            ]
        }
    ]
}

### 3. IAMでTravisユーザ作成
UserName: Travis
access type: Programmatic access
Set permissions: 上記で作成したTravis-Deploy-To-S3、Travis-Code-Deploy-Policy
->作成後、accesskey、secretkeyを保存

### 4. EC2のロール作成
Create role -> AWS service EC2
Permissions:CodeDeployDemo-EC2-Permissions
Role Name: CodeDeploy_EC2_DEPLOY_INSTANCE

### 5. CodeDeployアプリの為のロール作成
Create role -> CodeDeploy
Permissions: AWSCodeDeployRole
Role Name: CodeDeployServiceRole

### 6. EC2 launch
Amazon Linux 2 AMI (HVM), SSD Volume Type 64x t2.nano 8GiB GP2
Auto-assign Public IP: enable
IAM role: CodeDeploy_EC2_DEPLOY_INSTANCE
Tag: Name travisci

### 7. S3バケット作成
create bucket -> demo-travis-s3

### 8. CodeDeploy作成
Create application -> application nameはIAMのTravis-Code-Deploy-Policyで設定したname
platform: EC2/On-premises

Create Deployment Group -> Deployment Group Name : TravisCodeDeployDemoDeploymentGroup(何でもOK)
Envrionment Configuration -> Amazon EC2 -> 6で作成したtagを選択(Name travisci)
CodeDeployDefault.AllAtOnce

### 9. travis.yml

language: php
php:
  - 7.3

services:
  - mysql

before_script:
  - cp .env.travis .env
  - mysql -e 'create database test;'
  - composer self-update
  - composer install
  - chmod -R 777 storage

script: 
  - ./vendor/bin/phpunit

deploy:
  - provider: s3
    access_key_id: $AWS_ACCESS_KEY
    secret_access_key: $AWS_SECRET_KEY
    local_dir: dpl_cd_upload
    skip_cleanup: true
    on: &2
      repo: hoge/hogehoge
    bucket: demo-travis-s3
    region: ap-northeast-1
  - provider: codedeploy
    access_key_id: $AWS_ACCESS_KEY
    secret_access_key: $AWS_SECRET_KEY
    bucket: demo-travis-s3
    key: latest.zip
    bundle_type: zip
    application: travisci
    deployment_group: TravisCodeDeployDemoDeploymentGroup
    region: ap-northeast-1
    on: *2

script:
  - zip -r latest *
  - mkdir -p dpl_cd_upload
  - mv latest.zip dpl_cd_upload/latest.zip

### 10.Travis側でcrudentialの登録
Environment Variables
– AWS_ACCESS_KEY, AWS_SECRET_KEYを入力

### 11. EC2にCodeDeployインストール
$ sudo yum update
$ sudo yum install ruby
$ sudo yum install aws-cli
$ aws s3 cp s3://aws-codedeploy-ap-northeast-1/latest/install . –region ap-northeast-1
$ chmod +x ./install
$ sudo ./install auto
$ sudo service codedeploy-agent status
$ sudo yum info codedeploy-agent

### 12. appspec.yml

version: 0.0
os: linux
files:
  - source: ./
    destination: /home/test/travisci

### 13. git push & deploy
$ git push -u origin master

### 14. travisci
-> passed
-> Done. Your build exited with 0.

### 15. EC2で動作確認
$ cd /home/test/travisci
$ ls
README.md artisan composer.lock database phpunit.xml routes tests
app bootstrap composer.phar package-lock.json public server.php vendor
appspec.yml composer.json config package.json resources storage webpack.mix.js

– 所感
circleCIはデプロイのjob実装に一日かかりましたが、Travisは多少IAMの設定に時間がかかりましたが、デプロイは一発で上手くいきました。
Gitpullではなく、CodeDeployでデプロイできるので、AWSとはTravisの方が相性が良さそう。
ただ、unitテストはmasterへのpushではなく、ブランチのリポジトリへのpushのタイミングの方が良さそう。

CircleCIからEC2にデプロイする際にThe authenticity of host ” can’t be establishedが出た時

$ ssh-keygen -m pem
$ cd .ssh
$ ls
authorized_keys config id_rsa id_rsa.pub

id_rsa(秘密鍵)を Circle CI -> PROJECT SETTINGS -> Add SSH Keyに登録
その際、Host NameはインスタンスのIPアドレスを登録する

id_rsa.pub(公開鍵)をEC2 .ssh/authorized_keysに追加

$ git push -u origin master
The authenticity of host ‘************* (*************)’ can’t be established.

config.yml

      - run: ssh -o 'StrictHostKeyChecking no' ${USER_NAME}@${PUBLIC_IP} 'cd /var/www && git pull'
#!/bin/bash -eo pipefail
ssh -o 'StrictHostKeyChecking no' ${USER_NAME}@${PUBLIC_IP} 'cd /var/www && git pull'
Warning: Permanently added '*************' (ECDSA) to the list of known hosts.

fatal: not a git repository (or any of the parent directories): .git

Exited with code exit status 128

あ、エラー内容が変わりました。

$ cd /var/www
$ sudo git clone https://github.com/hoge/circleci.git

config.yml

      - run: ssh -o 'StrictHostKeyChecking no' ${USER_NAME}@${PUBLIC_IP} 'cd /var/www/circleci && git pull'

error: cannot open .git/FETCH_HEAD: Permission denied
$ sudo chmod 777 .git/
$ git remote add origin https://{username}:{password}@github.com/{username}/project.git

error: insufficient permission for adding an object to repository database .git/objects
fatal: failed to write object
fatal: unpack-objects failed

$ sudo chmod 777 objects/

error: cannot lock ref ‘refs/remotes/origin/master’: Unable to create ‘/var/www/circleci/.git/refs/remotes/origin/master.lock’: Permission denied

$ git remote prune origin

There is no tracking information for the current branch.
Please specify which branch you want to merge with.

error: unable to unlink old ‘.circleci/config.yml’: Permission denied
error: unable to unlink old ‘resources/views/home.blade.php’: Permission denied

$ sudo chown -R ec2-user ./

やっといけました。1日かかりました。
他の方は ssh -o ‘StrictHostKeyChecking no’やgitのpermission変更などせずに行けているようなのであまり参考にならないかもしれませんが。

Circle CIでEC2にデプロイ

### 環境
– vagrant Amazon Linux2
– Laravel7.2.1, Mysql8.0

### 前提
– .circleci/config.ymlを配置済み
– git pushすると、phpunitが走る
– これにデプロイのjobを追加したい

公式: https://circleci.com/docs/ja/2.0/deployment-integrations/

公式のソースコード:
-> runコマンドを見るとgit pushでデプロイしていますね。

deploy:
    machine:
        enabled: true
    working_directory: ~/circleci-demo-workflows
    environment:
      HEROKU_APP: "sleepy-refuge-55486"
    steps:
      - checkout
      - run:
          name: Master を Heroku にデプロイ
          command: |
            git push https://heroku:$HEROKU_API_KEY@git.heroku.com/$HEROKU_APP.git master

workflows:
  version: 2
  build-and-deploy:
    jobs:
      - build
      - deploy:
          requires:
            - build
          filters:
            branches:
              only: sequential-branch-filter

ec2にsshログインしているので、これをconfig.ymlに書いてやってみたいと思います。

ssh ec2-user@{publicIP} -i  ~/.ssh/***.pem

### 1. テスト用のEC2インスタンス作成
– Amazon Linux 2 AMI (HVM), SSD Volume Type 64bit
– t2.nano
– public subnet
– Auto-assign Public IP: enable
– gp2 8GiB
– SecurityGroup: SSH 0.0.0.0/0
– keypair: create | select

->SSHログインテスト
ssh ec2-user@{publicIP} -i ~/.ssh/***.pem

### 2. EC2にGitインストール
// インストール手順は省略
$ git –version
git version 2.19.2

$ cd /var
$ sudo mkdir www

### 3. CircleCI Project setting
CircleCIのコンソールにログインし、対象リポジトリのproject settingのページに遷移
– Environment Variables
KEY: PUBLIC_IP, VALUE: **.***.***.**
KEY: USER_NAME, VALUE: ec2-user

– SSH Permissions
Hostname: 任意
Private Key:秘密鍵の中身

-----BEGIN RSA PRIVATE KEY-----
// 省略
-----END RSA PRIVATE KEY-----

### 4.config.ymlにdeploy追加

version: 2
jobs:
  build:
    // buildは省略
  deploy:
    machine:
      image: circleci/classic:edge
    steps:
      - checkout
      - add_ssh_keys:
      - run: ssh ${USER_NAME}@${PUBLIC_IP} 'cd /var/www && git pull

workflows:
  version: 2
  build_and_deploy:
    jobs:
      - build
      - deploy:
        requires:
          - build
        filters:
          branches:
            only: master

### 5.git push
$ git push -u origin master
$ echo -e “Host github.com\n\tStrictHostKeyChecking no\n” > ~/.ssh/config

#!/bin/bash -eo pipefail
ssh ${USER_NAME}@${PUBLIC_IP} ‘cd /var/www && git pull’
The authenticity of host ‘************* (*************)’ can’t be established.

buildはsuccessだがdeployが何度やってもダメだ。。。丸一日潰れた。

ん?

EC2 インスタンス上で秘密鍵 (pem ファイル) を作成して CircleCI に登録する必要があります。

秘密鍵はec2で作成するの???
あああああああああ

アジャイルとウォーターフォール

開発の性格や規模によって、どちらが適している、いないなどがある

ウォーターフォール
– 正確性、信頼性が求められる場合は適している
– 要件定義に時間をかける
– 出戻りがない想定

アジャイル
– スピード重視
– ドキュメントに時間をかけない
– 少人数で回す
– PDCAを回して改善していく
– 仕様変更にも柔軟に対応する