Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Rails App Deployment with CodeDeploy
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
tannai
August 30, 2016
Programming
1.6k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Rails App Deployment with CodeDeploy
http://classmethod.connpass.com/event/38180/
tannai
August 30, 2016
More Decks by tannai
See All by tannai
redash patche at dmm
yuukigoodman
0
770
akibago-2018-10-30
yuukigoodman
0
91
serverless-design-and-streaming-date-processing-service
yuukigoodman
0
1.1k
alexa-changes-development-process
yuukigoodman
0
1.7k
VUIとAlexaによるちょっと未来の体験の話2
yuukigoodman
0
940
regrowth2016alexa
yuukigoodman
0
1.4k
cognito-userpools-in-production
yuukigoodman
4
8.9k
aws-lambda-in-practice
yuukigoodman
2
2.1k
serverless-from-today
yuukigoodman
2
2.3k
Other Decks in Programming
See All in Programming
Webの地図
yosuke_furukawa
PRO
6
4.3k
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
240
Swift愛好会100回記念 第1回を振り返る
jollyjoester
0
120
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
290
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
0
220
AIエージェント時代のコードレビューを設計する
nogu66
6
2.6k
週末にAI-DLCを本気で回したら$1,600溶けた
hbashimizu
0
130
初心者DevRelとして参加者だった私が、DevRel Talks!#2に登壇するまでにしてきたこと
sokohirai
0
370
Can LLMs Replicate 4 Years of Compose Migration? Exploring the boundaries of automation with 279 XML files from a real product
makun
0
130
コンパウンドプロダクト開発のためのローカルプロセスマネージャー再発明 #layerxgo
izumin5210
0
670
AIとGame Jamで、ゲームを完成させた話
takahirosaeki
0
120
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
4
660
Featured
See All Featured
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.6k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
660
The Cult of Friendly URLs
andyhume
79
7k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
410
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Evolving SEO for Evolving Search Engines
ryanjones
0
290
SEO for Brand Visibility & Recognition
aleyda
0
4.7k
Designing for humans not robots
tammielis
254
26k
Crafting Experiences
bethany
1
330
Leo the Paperboy
mayatellez
9
2.3k
The SEO Collaboration Effect
kristinabergwall1
1
550
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Transcript
RailsΞϓϦΛ σϓϩΠ͢Δ CodeDeploy Classmethod, Inc. Yuki Tannai ࣮ફAWSϓϩάϥϛϯά
ࣗݾհ • ୮༏ل • @yuukigoodman • αʔόͰಈ͘ϓϩάϥϜͱ͔AWS
Agenda • σϓϩΠͱ • σϓϩΠΛࢧ͑ΔAWS • CodeDeployͰRailsΛσϓϩΠ
σϓϩΠͱ
γεςϜΛ ར༻Մೳʹ͢Δ ׆ಈશൠͰ͋Δ — ja.wikipedia.org1 1 https://ja.wikipedia.org/wiki/ιϑτΣΞσϓϩΠϝϯτ
• ͨͩίʔυΛμϯϩʔυͯ͠ىಈ͢Εྑ͍ ͱ͍͏ͷͰͳ͍ • σϓϩΠʹΑͬͯղܾ͍͕ͨ͋͠Γɺ ͦΕϓϩδΣΫτͷਐߦͱڞʹมԽ͢Δ • σϓϩΠαʔϏεఏڙऀͷΛղܾ͢Δ • ఏڙऀͷղܾར༻ऀͷՁʹͳΓಘΔ
• σϓϩΠ࣭ͷͻͱͭ(QCD) • Quality/Cost/Delivery
σϓϩΠࣗಈԽͷಈػ • ස͕ଟ͍ • ϛε͕Ͱ͖ͳ͍ • ϧʔνϯϫʔΫ • ͰʑมΘΔ ࣗಈԽ͠ͳ͍ͱͬͯΒΜͶʔʂʂ
σϓϩΠࣗಈԽͷ؍ • Ͳ͔͜ΒͲ͜ʹσϓϩΠ͢Δ͔ • ࣗಈσϓϩΠͷ࣮ߦτϦΨʔ • ͍ͭ୭͕σϓϩΠ͢Δ͔ • ࣦഊΛͲ͏ݕग़͠ɺͲ͜ʹ௨͢Δ͔ •
Ͳͷ͘Β͍มߋ͕ೖΔ͔
σϓϩΠϓϩδΣΫτͷਐߦͱͱʹมԽ͢Δ • Ϗδωε: ༷มߋೲظॖ • ৫: ϝϯόʔͷೖΕସ͑૿ݮɺख़ͷෆ ۉҰ͞ • ٕज़:
όʔδϣϯΞοϓύϑΥʔϚϯε ͜ΕΒͷཧ༝ʹΑΓσϓϩΠมߋ͞ΕΔ
มߋʹ͑͏Δ σϓϩΠࣗಈԽͷ ϓϩάϥϜΛॻ͘
ͦͷͨΊͷඪઃఆͱઃܭ͕େࣄ
σϓϩΠΛࢧ͑Δ AWS
None
EC2 • ΦʔιυοΫεͳσϓϩΠλʔήοτ • େͷ߹EC2ʹσϓϩΠ͢Δ • Πϯελϯε࡞ͱϓϩϏδϣχϯά͕ඞཁ
None
Elastic Beanstalk • HerokuΈ͍ͨͳαʔϏε • EC2/RDS/ELBϦιʔεΛ؆୯ʹཧ͢Δ • ࣮ମCFn • ઐ༻ͷίϚϯυ(eb-cli)͕͋Δ
• eb deploy
None
Cloud Formation • AWSϦιʔεͷߏཧ • ϒϥβCLIͰ͍ͬͯΔ͜ͱΛJSONͰهड़ ͢Δͱ࣮ߦͯ͘͠ΕΔ • AWSެࣜఏڙπʔϧͳͷͰ҆৺ •
࠶ݱੑ͕ٻΊΒΕΔ߹ඇৗʹ༗ޮ
None
EC2 Container Service • EC2Ϋϥελ্Ͱͷίϯςφ࣮ߦΛཧ • Dockerӡ༻ʹৄ͍͠ਓɺ ͥͻ࠙ձͰڭ͍͑ͯͩ͘͞ >< •
Container Registry౦ژʹདྷͨ
None
Code Deploy • EC2ͷίʔυͷஔͱىಈΛཧ͢ΔαʔϏε • ຊͷओਓެ • EC2ʹAgentΛΠϯετʔϧ͓ͯ͘͠
CodeDeployͰ RailsΛσϓϩΠ
େ·͔ͳྲྀΕ • Ansible Playbookͷ࡞ • CodeDeployઃఆͷ࡞ • Cloud Formation Templateͷ࡞
• σϓϩΠͯ͠ΈΔ • Ճཁ݅Λ࣮͢Δ • ࣦഊ࣌ͷ௨ • Blue Green Deployment
Ansible Playbookͷ࡞
webservers.yml - hosts: all remote_user: ec2-user vars: rails_env: "{{ lookup('env',
'RAILS_ENV') }}" roles: - common - nginx - fluentd - logrotate - ruby - node - rails - ssh
roles/common/tasks/main.yml - name: install yum security plugin yum: pkg=yum-plugin-security state=latest
sudo: yes - name: update yum security shell: yum -y --security update-minimal sudo: yes
roles/common/tasks/main.yml - name: install yum packages yum: name={{ item }}
state=present sudo: yes with_items: - gcc-c++ - glibc-headers - openssl-devel - readline - readline-devel - libyaml-devel - libffi-devel - libxml2 - libxslt - libxml2-devel - libxslt-devel - zlib - zlib-devel - mysql-devel - git - ruby-devel
roles/node/tasks/main.yml - name: install nodejs yum: name=nodejs enablerepo=epel sudo: yes
roles/ruby/tasks/main.yml - name: check rbenv presence command: which rbenv ignore_errors:
true register: rbenv_path - name: Install rbenv sudo: yes git: repo=https://github.com/sstephenson/rbenv.git dest={{ rbenv_root }} when: rbenv_path.rc != 0 - name: Install ruby-build sudo: yes git: repo=https://github.com/sstephenson/ruby-build.git dest={{ rbenv_root }}/plugins/ruby-build when: rbenv_path.rc != 0
roles/ruby/tasks/main.yml - name: create shims dir sudo: yes file: path={{
rbenv_root }}/shims state=directory when: rbenv_path.rc != 0 - name: create versions dir sudo: yes file: path={{ rbenv_root }}/versions state=directory when: rbenv_path.rc != 0 - name: change owner of install dir sudo: yes command: chgrp -R {{ app_user }} {{ rbenv_root }} when: rbenv_path.rc != 0 - name: change mode of install dir sudo: yes command: chmod -R g+rwxXs {{ rbenv_root }} when: rbenv_path.rc != 0
roles/ruby/tasks/main.yml - name: Set rbenv env file sudo: yes copy:
src=rbenv.sh dest=/etc/profile.d mode=0775 when: rbenv_path.rc != 0 - name: check ruby version shell: rbenv versions | grep {{ ruby_version }} > /dev/null ; echo $? ignore_errors: true register: ruby_is_installed changed_when: ruby_is_installed.stdout != '0' - name: Install ruby with rbenv shell: bash -lc "rbenv install {{ ruby_version }}" args: creates: "{{ rbenv_root }}/versions/{{ ruby_version }}/bin/ruby"
roles/ruby/tasks/main.yml - name: check ruby version shell: ruby -v |
grep {{ ruby_version }} > /dev/null ; echo $? register: is_correct_version changed_when: is_correct_version.stdout != '0' - name: Switch Ruby version shell: bash -lc "rbenv global {{ ruby_version }} && rbenv rehash" when: is_correct_version.stdout != '0' - name: update rubygems shell: bash -lc "rbenv exec gem update --system" - name: install common gems shell: bash -lc "rbenv exec gem install bundler io-console --no-ri --no-rdoc" args: creates: "{{ rbenv_root }}/shims/bundle"
CodeDeployઃఆͷ࡞
RAILS_ROOT/appspec.yml version: 0.0 os: linux files: - source: / destination:
/home/ec2-user/app permissions: - object: /home/ec2-user pattern: "**" owner: ec2-user group: ec2-user mode: 755
RAILS_ROOT/appspec.yml hooks: ApplicationStop: - location: script/codedeploy/deregister_from_elb.sh - location: script/codedeploy/application_stop.sh timeout:
300 runas: ec2-user BeforeInstall: - location: script/codedeploy/before_install.sh timeout: 300 runas: root
RAILS_ROOT/appspec.yml AfterInstall: - location: script/codedeploy/after_install.sh timeout: 3600 runas: ec2-user ApplicationStart:
- location: script/codedeploy/application_start.sh timeout: 3600 runas: ec2-user ValidateService: - location: script/codedeploy/verify_service.sh timeout: 3600 runas: ec2-user - location: script/codedeploy/register_with_elb.sh
ApplicationStop • σϓϩΠલʹΞϓϦΛఀࢭ͢Δ • ELBԼͷ߹ొղআ͢Δ • EC2ࣗΛstand byʹ͢Δ • deregister_from_elb.sh
awslabsϦϙͰ
ApplicationStop • application_stop.shͰదٓRailsΛఀࢭ͢ Δ • ͜ͷ࣌ͰELB͔Βִ͞Ε͍ͯΔͷͰࢭΊ ͳͯ͘ྑ͍
BeforeInstall • ιʔείʔυΛEC2ʹίϐʔ͢Δ • ओʹAnsible(ͱCapistrano)ͷ४උ • appspec.ymlͰrunas: rootΛΕͳ͍
BeforeInstall #!/bin/bash yum list installed python-pip &> /dev/null if [
$? != 0 ]; then yum install -y python-pip fi pip list | grep -q ansible if [ $? != 0 ]; then pip install ansible fi mkdir -p /data/app chown -R ec2-user:ec2-user /data/app
AfterInstall • ίϐʔͱunzipͷ࣍ʹ࣮ߦ͞ΕΔ • ࣗͷEC2λάΛಡΜͰઃఆϑΝΠϧΛμϯ ϩʔυͯ͠ධՁ
AfterInstall #!/bin/bash set -u METADATA=`ec2-describe-instances $(ec2-metadata -i | cut -d"
" -f 2) --region ap-northeast-1` BUCKET_NAME=`echo "$METADATA" | grep VariablesBucket | cut -f 5` KEY_NAME=`echo "$METADATA" | grep VariablesKey | cut -f 5` sudo aws s3api get-object --bucket $BUCKET_NAME \ --key $KEY_NAME $APPLICATION_VARIABLES_PATH \ --region ap-northeast-1 . $APPLICATION_VARIABLES_PATH /usr/local/bin/ansible-playbook $DESTINATION_PATH/ansible/site.yml \ -i $DESTINATION_PATH/ansible/codedeployhosts --connection=local
ApplicationStart • Railsͷىಈ४උͱىಈΛߦͳ͏ • ࠓճcapistranoͰٵऩ͍ͯ͠Δ
ApplicationStart #!/bin/bash set -u . /etc/profile.d/rbenv.sh . $APPLICATION_VARIABLES_PATH cd $DESTINATION_PATH
rbenv exec bundle exec cap local deploy
ValidateService • ΞϓϦέʔγϣϯͷىಈͱELBొΛߦͳ͏ • ҎԼͷεΫϦϓτ͕exit code 0ͳΒ࣍ͷ registerwithelb.sh͕Δ • registerwithelb.shAWSLabsͰެ։͞
Ε͍ͯΔ #!/bin/bash curl -s http://localhost/health_check
Cloud Formation Templateͷ࡞
ͦΕΛه͢ʹ ༨ന͕Γͳ͍
ͬͯΔ͜ͱ • ELBͷ࡞ • Launch Configͷ࡞ • User DataͰCodeDeploy AgentͷΠϯε
τʔϧ • Auto Scaling Groupͷ࡞ • Route53Ϩίʔυͷ࡞ ※CodeDeployϦιʔε࡞ͯ͠ͳ͍
Launch Config "UserData": { "Fn::Base64": { "Fn::Join": [ "", [
"#!/bin/bash -xe\n", "yum update -y aws-cfn-bootstrap; yum install -y aws-cli\n", "sed -i 's/Defaults requiretty/Defaults:root !requiretty/g' /etc/sudoers\n", "cd /home/ec2-user/\n", "aws s3 cp 's3://aws-codedeploy-us-east-1/latest/codedeploy-agent.noarch.rpm' . ", "|| error_exit 'Failed to download AWS CodeDeploy Agent.'\n", "yum -y install codedeploy-agent.noarch.rpm || error_exit 'Failed to install AWS CodeDeploy Agent.' \n" ] ] } },
CFn Create Stack
CodeDeployϦιʔεΛखಈͰ࡞ • ڥมshΛS3ʹஔ͘ • CFnͰͰ͖ͨASGΛࢦఆͯ͠Aplication/ DeploymentGroup࡞
σϓϩΠͯ͠ΈΔ
Ճཁ݅: ΑΓҰͷࣗಈԽ
ྲྀΕ • εΫϦϓτͰσϓϩΠ༻zipΛ࡞ • S3ʹஔ • LambdaͰCodeDeploy
εΫϦϓτͰσϓϩΠ༻zipΛ࡞ gulp.task('clean', function() { return del(['./tmp/dest']); }); gulp.task('zip', function() {
return gulp.src('**') .pipe(excludeGitignore()) .pipe(zip(bundleName + '.zip')) .pipe(gulp.dest('./tmp/dest')); }); gulp.task('upload', function(){ var publisher = awspublish.create({ params: { Bucket: BUCKET } }); return gulp.src('./tmp/dest/' + bundleName + '.zip') .pipe(publisher.publish()) .pipe(awspublish.reporter()); });
S3ʹzipΛஔ͘ͱಈ͘Lambda exports.handler = (event, context, callback) => { const message
= JSON.parse(event.Records[0].Sns.Message); const params = { applicationName: `my-application`, deploymentGroupName: `my-deployment-group`, revision: { revisionType: 'S3', s3Location: { bucket: message.bucketName, bundleType: 'zip', key: message.keyName } } };
S3ʹzipΛஔ͘ͱಈ͘Lambda codedeploy.createDeployment(params, (err, data) => { if (err) { console.log(err);
callback(err); } else { callback(null, data); } });
Ճཁ݅: ىಈΛૣ͘͢Δ
AMIΛͱΔ • σϓϩΠঢ়ଶͷAMI࡞ • CFnमਖ਼
Ճཁ݅: B-G σϓϩΠ
• ELB+ASGΛDeploymentGroupΛ2ͭ࡞ • CodeDeloyޭ࣌ʹSNSܦ༝ͰLambdaΛىಈ • LambdaͰRoute53 ALIASϨίʔυͷ͖ઌΛ ม͑Δ
·ͱΊ
CodeDeployͰҎԼΛୡՄೳ • AnsibleγΣϧεΫϦϓτͷφϨοδΛస༻ Ͱ͖Δ • χʔζʹ߹ΘͤͨσϓϩΠγεςϜΛ࡞ΕΔ