CircleCIでOrbsのCommands使って
ECS/Fargateデプロイようやくできた🤟
これはあとでブログする💪— adachin👾SRE (@adachin0817) February 28, 2020
前回のブログではCircleCIでデプロイする前にDockerfileでやることをブログしましたが、今回はstg環境をリリースするまでCircleCIのOrbsでECR/ECS/Fargateにデプロイする方法を紹介したいと思います!ようやく実現できたので、まずは構成からいってみましょう。
■構成
- ディレクトリ構成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
> tree . └── .circleci ├── config.yml └── Gemfile └── Gemfile.lock └── docker └── stg ├── app ├── .env.example ├── Dockerfile ├── gemrc ├── nginx │ ├── adachin.conf │ └── nginx.conf └── supervisor └── app.conf |
CircleCIの流れは以下。(rspecも同時に動いています)今まではimageをpushしてECSのリビジョンの更新と、サービスのタスク定義の更新まで ecs-deployを使ってデプロイしていましたが、Orbsを使って簡単にデプロイできるようになりました。
https://www.publickey1.jp/blog/20/circleciawsgoogle_cloudkubernetesorb.html
- Githubでdevelopブランチにプルリクを出す
- add .env、Dockerfile buid、copy source、bundle install
- imageをECRにpush
- ECSリビジョン更新、サービスのタスク定義の更新
- DBマイグレーション
■Dockerfile/CircleCI
- app/docker/stg/adachin-app/Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
FROM ruby:2.5.7 ENV LANG C.UTF-8 ENV ENTRYKIT_VERSION 0.4.0 ENV QMAKE=/usr/lib/qt5/bin/qmake ENV APP_ROOT /var/www/app # Setup UTC+9 RUN cp -p /etc/localtime /etc/localtime.UTC \ && cp -p /usr/share/zoneinfo/Japan /etc/localtime RUN apt-get update -y && \ apt-get upgrade -y && \ apt-get install -y --no-install-recommends \ bash \ build-essential \ default-mysql-client \ git \ libcurl4-openssl-dev \ libghc-yaml-dev \ libqt5webkit5-dev \ libxml2-dev \ libxslt-dev \ libyaml-dev \ linux-headers-amd64 \ locales \ nginx \ nodejs \ openssl \ ruby-dev \ ruby-json \ ssh \ sudo \ supervisor \ tzdata \ vim \ zlib1g-dev && \ apt-get clean -y && \ rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* RUN wget https://github.com/progrium/entrykit/releases/download/v${ENTRYKIT_VERSION}/entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \ && tar -xvzf entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \ && rm entrykit_${ENTRYKIT_VERSION}_Linux_x86_64.tgz \ && mv entrykit /bin/entrykit \ && chmod +x /bin/entrykit \ && entrykit --symlink # setting locales RUN localedef -f UTF-8 -i en_US en_US.UTF-8 # copy app RUN mkdir -p $APP_ROOT COPY . $APP_ROOT WORKDIR /var/www/app RUN mkdir -p /root/tmp # build nokogiri COPY docker/stg/adachin-app/gemrc/.gemrc /etc/gemrc/ RUN chmod +r /etc/gemrc RUN bundle config --global build.nokogiri --use-system-libraries # bundle install RUN cp -r docker/stg/adachin-app/.bundle . RUN bundle install --path vendor/bundle RUN bundle exec rake assets:stgcompile RAILS_ENV=stg # aws-cli install RUN curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py" RUN python get-pip.py && sudo pip install awscli RUN rm get-pip.py # nginx RUN groupadd nginx RUN useradd -g nginx nginx ADD docker/stg/adachin-app/nginx/nginx.conf /etc/nginx/nginx.conf ADD docker/stg/adachin-app/nginx/adachin.conf /etc/nginx/conf.d/adachin.conf # Create adachin user RUN adduser --disabled-password --home /home/adachin adachin RUN echo "adachin ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers COPY docker/stg/adachin-app/common/prompt.sh /etc/profile.d/ RUN chmod 755 /etc/profile.d/prompt.sh COPY docker/stg/adachin-app/common/.bashrc /home/adachin/ # Add authorized_keys RUN sudo -u adachin mkdir /home/adachin/.ssh RUN mv authorized_keys /home/adachin/.ssh/ RUN chmod 600 /home/adachin/.ssh/authorized_keys RUN chown adachin:adachin /home/adachin/.ssh/authorized_keys # Add aws credentials RUN mkdir /home/adachin/.aws RUN mv credentials /home/adachin/.aws/ RUN sudo chown adachin:adachin /home/adachin/.aws/credentials # Setup ssh RUN sed -ri 's/^#Port 22/Port 123456/' /etc/ssh/sshd_config RUN sed -ri 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config RUN sed -ri 's/^UsePAM yes/UsePAM no/' /etc/ssh/sshd_config RUN sed -ri 's/^#PermitUserEnvironment no/PermitUserEnvironment no/' /etc/ssh/sshd_config RUN ssh-keygen -A RUN mkdir -p /run/sshd # setting superviser COPY docker/stg/adachin-app/supervisor/app.conf /etc/supervisor/conf.d/app.conf COPY docker/stg/adachin-app/supervisor/delayed_job.sh /etc/supervisor/conf.d/delayed_job.sh RUN chmod 755 /etc/supervisor/conf.d/delayed_job.sh # link logs RUN ln -sf /dev/stdout /var/log/nginx/access.log RUN ln -sf /dev/stderr /var/log/nginx/error.log RUN ln -sf /dev/stdout /var/www/app/log/delayed_job.log # Service to run CMD [ "/usr/bin/supervisord" ] |
- .circleci/config.yml
https://circleci.com/orbs/registry/orb/circleci/aws-ecr
https://circleci.com/orbs/registry/orb/circleci/aws-ecs
※追記
Commandsだと乱雑化してしまうので、Jobsで管理したほうがもっとシンプルで見やすくなるので以下を参考にしてください。またOrbsも最新バージョンとなっています。(2021/04/22)
https://github.com/RVIRUS0817/circleci_plaza/blob/master/ecs_rails-deploy/config.yml-latest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
version: 2.1 orbs: aws-ecr: circleci/aws-ecr@6.7.0 aws-ecs: circleci/aws-ecs@1.1.0 executors: default: docker: - image: circleci/ruby:2.5.7-stretch environment: BUNDLE_JOBS: 3 BUNDLE_RETRY: 3 BUNDLE_PATH: vendor/bundle RAILS_ENV: test DATABASE_HOST: '127.0.0.1' DATABASE_USER: 'root' - image: circleci/mysql:5.7 environment: MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' MYSQL_HOST: '%' docker_build: machine: docker_layer_caching: true commands: bundle_install_rspec: steps: - run: name: copy config files command: | cp config/mail.yml.example config/mail.yml - run: name: Which bundler? command: bundle -v - restore_cache: keys: - cache-gem-{{ checksum "Gemfile.lock" }} - cache-gem- - run: name: Bundle Install command: bundle check || bundle install - save_cache: key: cache-gem-{{ checksum "Gemfile.lock" }} paths: - vendor/bundle - run: name: Database create command: DISABLE_SPRING=true bin/rake db:create --trace - run: name: Database setup command: DISABLE_SPRING=true bin/rake db:schema:load --trace - run: name: Run rspec command: | TZ=Asia/Tokyo \ bundle exec rspec --profile 10 \ --out test_results/rspec.xml \ --format progress \ $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings) ## stg build_and_push_docker_image_app_devops_stg: steps: - aws-ecr/build-and-push-image: account-url: AWS_ECR_ACCOUNT_URL_stg aws-access-key-id: AWS_ACCESS_KEY_ID_stg aws-secret-access-key: AWS_SECRET_ACCESS_KEY_stg region: AWS_REGION repo: 'adachin-app-stg' dockerfile: docker/stg/adachin-app/Dockerfile tag: "${CIRCLE_SHA1}" - aws-ecs/update-service: family: 'adachin-app' service-name: 'adachin-app-service' cluster-name: 'adachin' container-image-name-updates: 'container=adachin-app,image-and-tag=${AWS_ECR_ACCOUNT_URL_stg}/adachin-app-stg:${CIRCLE_SHA1}' - aws-ecs/update-service: family: 'adachin-devops' service-name: 'adachin-devops-service' cluster-name: 'adachin' container-image-name-updates: 'container=adachin-devops,image-and-tag=${AWS_ECR_ACCOUNT_URL_stg}/adachin-app-stg:${CIRCLE_SHA1}' db_migrate_app_stg: steps: - aws-ecs/run-task: cluster: 'adachin' task-definition: 'adachin-app' count: 1 launch-type: FARGATE awsvpc: true subnet-ids: subnet-xxxxxxx,subnet-xxxxxxx,subnet-xxxxxxx security-group-ids: sg-xxxxxxx overrides: "{\\\"containerOverrides\\\":[{\\\"name\\\": \\\"adachin-app\\\",\\\"command\\\": [\\\"bundle\\\", \\\"exec\\\", \\\"rake\\\", \\\"db:migrate\\\", \\\"RAILS_ENV=stg\\\"]}]}" jobs: rspec: working_directory: ~/rspec executor: default steps: - checkout - bundle_install_rspec deploy_app_devops_stg: working_directory: ~/app executor: default steps: - setup_remote_docker - checkout - run: name: echo authorized_keys command: | echo ${DEVOPS_KEY_STG} >> authorized_keys - run: name: install awscli command: | sudo apt-get install awscli -y - run: name: setting aws configure command: | aws configure set aws_access_key_id ${AWS_ACCESS_KEY_ID_STG_S3} \ && aws configure set aws_secret_access_key ${AWS_SECRET_ACCESS_KEY_STG_S3} - run: name: download .env command: | aws s3 cp s3://pre-adachin.com/stg/env .env - run: name: copy and echo mail.yml command: | cp config/mail.yml.example config/mail.yml \ && sed -i "s/\${MAIL_PASS}/${MAIL_PASS}/g" config/mail.yml - run: name: copy and echo aws credentials command: | cp docker/stg/adachin-app/common/.aws/credentials credentials \ && sed -i "2i aws_access_key_id =${AWS_ACCESS_KEY_ID_STG_S3}" credentials \ && sed -i "3i aws_secret_access_key =${AWS_SECRET_ACCESS_KEY_STG_S3}" credentials - build_and_push_docker_image_app_devops_pre - db_migrate_app_stg workflows: version: 2 deploy_stg_and_rspec: jobs: - rspec - deploy_app_devops_stg: filters: branches: only: develop |
まずWorkflowsの Jobs
として rspec 25行目(CI)
と デプロイ 67行目(CD)
を分けており、環境変数は全て Environment Variables
で管理しています。また .env
の情報はGIthubでセキュリティ上管理したくないので、変数をCircleCI側の環境変数にechoで展開したく、Jobsだと制御できなかったため Commands
で実装しました。Githubにpushするだけでstg環境へリリースされるので、本番環境はmasterにマージされたらリリースするようにworkflowsに追加すればOKです。
- Jobs rspec
- Jobs build_push_stg
- ECS
ALBに反映されていればOK!
■まとめ
吾輩は勘違いをしていた。
— adachin👾SRE (@adachin0817) February 27, 2020
CircleCIってMacのローカルと同様にbuildするという概念と理解不足でめちゃくちゃハマりましたが、CircleCIはマジで何でもできるので、ECS/Fargateデプロイ初めてやる方は参考にしてみてください!
※追記
db:migrate方法について詳しくは以下を参考に。
[ECS/Fargate][run-task][Rails]CircleCI Orbsを使ってdb:migrateを行う
0件のコメント