<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shogo Kawahara</title>
    <description>The latest articles on DEV Community by Shogo Kawahara (@kawahara).</description>
    <link>https://dev.to/kawahara</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F49731%2F552e99bd-df91-4452-b4e4-6283e4b5f3c4.jpeg</url>
      <title>DEV Community: Shogo Kawahara</title>
      <link>https://dev.to/kawahara</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kawahara"/>
    <language>en</language>
    <item>
      <title>Making Lambda/API Gateway Environments for each git Branches</title>
      <dc:creator>Shogo Kawahara</dc:creator>
      <pubDate>Mon, 01 Jan 2018 08:52:35 +0000</pubDate>
      <link>https://dev.to/kawahara/make-lambdaapi-gateway-environments-for-each-git-branches-3785</link>
      <guid>https://dev.to/kawahara/make-lambdaapi-gateway-environments-for-each-git-branches-3785</guid>
      <description>&lt;p&gt;To test easily, our team tried to make Lambda/API Gateway environments for each git branches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background / Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We are using CircleCI for test and deployment.&lt;/li&gt;
&lt;li&gt;Web Application that is created with &lt;a href="https://serverless.com/"&gt;serverless&lt;/a&gt; and &lt;a href="https://github.com/awslabs/aws-serverless-express"&gt;serverless-express&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Your domain is managed by Route53, and SSL certificate is issued by Amazon Certificate manager on &lt;strong&gt;us-east-1&lt;/strong&gt; region&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install plugin
&lt;/h2&gt;

&lt;p&gt;To manage custom domain, install plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add -D serverless-domain-manager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configure serverless.yml
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To avoid creating S3 bucket creation for each branches, set &lt;code&gt;deploymentBucket&lt;/code&gt; into &lt;code&gt;serverless.yml&lt;/code&gt; in order to specify bucket place. &lt;/li&gt;
&lt;li&gt;To switch environment, serverless.yml load configuration from &lt;code&gt;./config/sls-config.yml&lt;/code&gt;.  (If you need to set secured variable, use KMS to encrypt it.)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# serverless.yml

service:
  name: ${self:custom.name}

provider:
  name: aws
  region: ap-northeast-1
  runtime: nodejs6.10
  stage: ${opt:stage, 'dev'}
  deploymentBucket:
    name: ${self:custom.name}.${self:provider.region}.deploy
  environment:
    XXX: ${self:custom.config.XXX, ''}
    YYY: ${self:custom.config.YYY, ''}

custom:
  name: project-name
  customDomain:
    domainName: ${self:provider.stage}.sls.example.com
    basePath: ''
    stage: ${self:provider.stage}
    certificateName: '*.sls.example.com'
    createRoute53Record: true
  config: ${file(./config/sls-config.yml)}

plugins:
  - serverless-domain-manager

functions:
  render:
    handler: server.render
    events:
      - http:
          path: '/'
          method: 'get'
          private: false
      - http:
          path: '{proxy+}'
          method: 'get'
          private: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Make configuration for each environments
&lt;/h2&gt;

&lt;p&gt;Make branch layout. For example, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;master&lt;/code&gt; branch = for production environment. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;develop&lt;/code&gt; branch = for development environment.&lt;/li&gt;
&lt;li&gt;Other branches = preview environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And make configuration file for each environments. And put object to any S3 Bucket with environment prefix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;production =&amp;gt; &lt;code&gt;s3://config-bucket/production/sls-config.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;development =&amp;gt; &lt;code&gt;s3://config-bucket/development/sls-config.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;preview =&amp;gt; &lt;code&gt;s3://config-bucket/preview/sls-config.yml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Make deployment script
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you cannot use &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;_&lt;/code&gt; to API Gateway stage name or CloudFormation template name. So this script removes these characters from git branch name. (e.g. &lt;code&gt;123-test-branch&lt;/code&gt; =&amp;gt; &lt;code&gt;123testbranch&lt;/code&gt;) It will be used for stage name for serverless framework.&lt;/li&gt;
&lt;li&gt;Set script file permission to 755.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# scripts/deploy.sh&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eu&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"preview"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CIRCLE_BRANCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"master"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CIRCLE_BRANCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"develop"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"development"&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;STAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CIRCLE_BRANCH&lt;/span&gt;&lt;span class="p"&gt;//[-\/]/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;echo &lt;/span&gt;&lt;span class="nv"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;STAGE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# get config file from S3&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;s3://config-bucket/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/sls-config.yml config/

&lt;span class="c"&gt;# make Route53 configuration&lt;/span&gt;
./node_modules/.bin/sls create_domain &lt;span class="nt"&gt;--stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$STAGE&lt;/span&gt;
&lt;span class="c"&gt;# deploy&lt;/span&gt;
./node_modules/.bin/sls deploy &lt;span class="nt"&gt;--stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$STAGE&lt;/span&gt;

&lt;span class="c"&gt;# remove old CloudFormation stacks when you delete remote branch&lt;/span&gt;
&lt;span class="nv"&gt;STACKS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;aws cloudformation list-stacks &lt;span class="nt"&gt;--stack-status-filter&lt;/span&gt; CREATE_COMPLETE CREATE_FAILED UPDATE_COMPLETE ROLLBACK_COMPLETE ROLLBACK_FAILED UPDATE_ROLLBACK_FAILED &lt;span class="nt"&gt;--max-items&lt;/span&gt; 1000 | jq &lt;span class="s1"&gt;'.StackSummaries[].StackName'&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'^project-name-'&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;BRANCHES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;git branch &lt;span class="nt"&gt;-r&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"s/^[[:space:]]*origin&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="s2"&gt;//"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"^HEAD"&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"stacks----"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;STACKS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"branches----"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BRANCHES&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;line
&lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;found&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

    &lt;span class="nv"&gt;lineStage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$line&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/^project-name-//'&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;

    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;branch
    &lt;span class="k"&gt;do
        &lt;/span&gt;&lt;span class="nv"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;//[-\/]/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$lineStage&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            &lt;/span&gt;&lt;span class="nv"&gt;found&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
            &lt;span class="nb"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;fi
    done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;END&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$BRANCHES&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="no"&gt;END

&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$found&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      ./node_modules/.bin/sls remove &lt;span class="nt"&gt;--stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$lineStage&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
      ./node_modules/.bin/sls delete_domain &lt;span class="nt"&gt;--stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$lineStage&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
    &lt;/span&gt;&lt;span class="k"&gt;fi

done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;END&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$STACKS&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="no"&gt;END
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configure &lt;code&gt;.circleci/config.yml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Your docker image for the deployment needs following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nodejs6&lt;/li&gt;
&lt;li&gt;python&lt;/li&gt;
&lt;li&gt;pip&lt;/li&gt;
&lt;li&gt;jq&lt;/li&gt;
&lt;li&gt;awscil&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And make &lt;code&gt;.circleci/config.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .circleci/config.yml

version: 2
jobs:
  build:
    docker:
      - image: my_docker_image
    parallelism: 1
    working_directory: ~/project-name
    steps:
      - checkout

      - restore_cache:
          key: project-name-yarn-{{ checksum "yarn.lock" }}

      - run:
          name: Install node modules
          command: yarn install

      - run:
          name: lint
          command: yarn run lint

      - run:
          name: unit
          command: yarn run unit

      - save_cache:
          key: project-name-yarn-{{ checksum "yarn.lock" }}
          paths:
            - ~/.yarn-cache

      - run:
          name: deploy
          command: scripts/deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Done!
&lt;/h2&gt;

&lt;p&gt;By this configuration, CircleCI will make Lambda/API Gateway environment to &lt;code&gt;${stagename}.sls.example.com&lt;/code&gt;. At first time to mapping domain, Route53 &amp;amp; CloudFront requires 40 minutes.&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>serverless</category>
      <category>lambda</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
