<?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>Forem: Serverless Guru</title>
    <description>The latest articles on Forem by Serverless Guru (@serverlessguru).</description>
    <link>https://forem.com/serverlessguru</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%2Forganization%2Fprofile_image%2F1973%2F6096690b-3e7f-43de-bd9c-be8f524317eb.png</url>
      <title>Forem: Serverless Guru</title>
      <link>https://forem.com/serverlessguru</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/serverlessguru"/>
    <language>en</language>
    <item>
      <title>Reusing S3 bucket for multiple Serverless Framework projects deploy</title>
      <dc:creator>Eduardo Rabelo</dc:creator>
      <pubDate>Mon, 24 Feb 2020 20:56:08 +0000</pubDate>
      <link>https://forem.com/serverlessguru/reusing-s3-bucket-for-multiple-serverless-framework-projects-deploy-5028</link>
      <guid>https://forem.com/serverlessguru/reusing-s3-bucket-for-multiple-serverless-framework-projects-deploy-5028</guid>
      <description>&lt;p&gt;When using Serverless Framework, the default behaviour is the creation of a S3 bucket for each &lt;code&gt;serverless.yml&lt;/code&gt; file, since they are treated as separated projects.&lt;/p&gt;

&lt;p&gt;As &lt;a href="https://serverless.com/framework/docs/providers/aws/guide/deploying/"&gt;described in the documentation&lt;/a&gt;, when you run serverless deploy we have the following steps happening:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An AWS CloudFormation template is created from your &lt;code&gt;serverless.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If a Stack has not yet been created, then it is created with no resources except for an &lt;strong&gt;S3 Bucket, which will store zip files of your Function code&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The code of your Functions is then packaged into zip files.&lt;/li&gt;
&lt;li&gt;Serverless fetches the hashes for all files of the previous deployment (if any) and compares them against the hashes of the local files.&lt;/li&gt;
&lt;li&gt;Serverless terminates the deployment process if all file hashes are the same.&lt;/li&gt;
&lt;li&gt;Zip files of your Functions’ code are uploaded to your Code S3 Bucket.&lt;/li&gt;
&lt;li&gt;Any IAM Roles, Functions, Events and Resources are added to the AWS CloudFormation template.&lt;/li&gt;
&lt;li&gt;The CloudFormation Stack is updated with the new CloudFormation template.&lt;/li&gt;
&lt;li&gt;Each deployment publishes a new version for each function in your service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html"&gt;AWS has a soft limit of 100 S3 buckets per account. You can increase your account bucket limit to a maximum of 1,000 buckets&lt;/a&gt;, but depending on your workload, this can still be a problem.&lt;/p&gt;

&lt;p&gt;How can you leverage the benefits of Serverless Framework and still keep your AWS sane? The answer relies on one option of the &lt;code&gt;serverless.yml&lt;/code&gt; file called &lt;code&gt;deploymentBucket&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Anatomy of "deploymentBucket" option
&lt;/h1&gt;

&lt;p&gt;In &lt;a href="https://serverless.com/framework/docs/providers/aws/guide/serverless.yml/"&gt;the &lt;code&gt;serverless.yml&lt;/code&gt; file reference&lt;/a&gt;, we can define a &lt;code&gt;provider.deploymentBucket&lt;/code&gt; and set the following options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# serverless.yml&lt;/span&gt;
&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="s"&gt;deploymentBucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.serverless.${self:provider.region}.deploys&lt;/span&gt;
    &lt;span class="na"&gt;maxPreviousDeploymentArtifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
    &lt;span class="na"&gt;blockPublicAccess&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;serverSideEncryption&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AES256&lt;/span&gt;
    &lt;span class="na"&gt;sseKMSKeyId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arn:aws:kms:us-east-1:xxxxxxxxxxxx:key/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa&lt;/span&gt;
    &lt;span class="na"&gt;sseCustomerAlgorithim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AES256&lt;/span&gt;
    &lt;span class="na"&gt;sseCustomerKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;sseCustomerKeyMD5&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;md5sum&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;key1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;value1&lt;/span&gt;
      &lt;span class="na"&gt;key2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;value2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Breaking down each option, we would have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: Deployment bucket name. Default is generated by the framework&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;maxPreviousDeploymentArtifacts&lt;/code&gt;: On every deployment, the framework prunes the bucket to remove artifacts older than this limit. The default is 5&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blockPublicAccess&lt;/code&gt;: Prevents public access via ACLs or bucket policies. Default is false&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;serverSideEncryption&lt;/code&gt;: server-side encryption method&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sseKMSKeyId&lt;/code&gt;: when using server-side encryption&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sseCustomerAlgorithim&lt;/code&gt;: when using server-side encryption and custom keys&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sseCustomerKey&lt;/code&gt;: when using server-side encryption and custom keys&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sseCustomerKeyMD5&lt;/code&gt;: when using server-side encryption and custom keys&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tags&lt;/code&gt;: Tags that will be added to each of the deployment resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To reuse the same bucket across multiple Serverless Framework projects, we need to set the same &lt;code&gt;deploymentBucket.name&lt;/code&gt; across these projects.&lt;/p&gt;

&lt;p&gt;Let’s create an example to understand it a little bit better.&lt;/p&gt;

&lt;h1&gt;
  
  
  Using "deploymentBucket" in multiple projects
&lt;/h1&gt;

&lt;p&gt;To illustrate a better scenario, let’s imagine the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;serverless.yml&lt;/code&gt; to define our bucket&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;serverless.yml&lt;/code&gt; for &lt;code&gt;serviceA&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;serverless.yml&lt;/code&gt; for &lt;code&gt;serviceB&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;serverless.yml&lt;/code&gt; for &lt;code&gt;serviceC&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We could translate it in the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;resources/
  s3/
    serverless.yml
services/
  serviceA/
    serverless.yml
  serviceB/
    serverless.yml
  serviceC/
    serverless.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And in our &lt;code&gt;resources/s3/serverless.yml&lt;/code&gt; we can add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;org&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-org-name&lt;/span&gt;
&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shared-app-name&lt;/span&gt;
&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:app}-shared-bucket-artifacts&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs12.x&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:stage, "dev"}&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:region, "us-west-2"}&lt;/span&gt;
  &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:profile, "default"}&lt;/span&gt;

&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;basename&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:service}-${self:provider.stage}&lt;/span&gt;
  &lt;span class="na"&gt;bucketname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.basename}-${self:provider.region}-artifacts&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;S3SharedBucketArtifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::S3::Bucket&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;BucketName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.bucketname}&lt;/span&gt;

&lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;S3SharedBucketArtifactsName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S3SharedBucketArtifacts&lt;/span&gt;
  &lt;span class="na"&gt;S3SharedBucketArtifactsArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;Fn::GetAtt: S3SharedBucketArtifacts.Arn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the file above, we’re defining an S3 bucket using CloudFormation and exporting it using Serverless Framework Pro feature called &lt;a href="https://serverless.com/framework/docs/dashboard/output-variables"&gt;&lt;strong&gt;Outputs&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While you can &lt;a href="https://medium.com/serverlessguru/supercharging-your-development-workflow-with-serverless-framework-pro-ae84ae6cc38b"&gt;supercharge your development workflow with Serverless Framework Pro&lt;/a&gt;, it is not a requirement. You can use CloudFormation export/import to achieve the same solution.&lt;/p&gt;

&lt;p&gt;Moving to &lt;code&gt;/services/serviceA/serverless.yml&lt;/code&gt;, we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;org&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-org-name&lt;/span&gt;
&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shared-app-name&lt;/span&gt;
&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:app}-serviceA&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs12.x&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:stage, "dev"}&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:region, "us-west-2"}&lt;/span&gt;
  &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:profile, "default"}&lt;/span&gt;
  &lt;span class="na"&gt;deploymentBucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.sharedBucketName}&lt;/span&gt;

&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;basename&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:service}-${self:provider.stage}&lt;/span&gt;
  &lt;span class="na"&gt;sharedBucketName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${output:${self:app}-shared-bucket-artifacts.S3SharedBucketArtifactsName}&lt;/span&gt;

&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./**&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;index.js&lt;/span&gt;

&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${self:custom.basename}-test&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.handler&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Returns "Hello World". Dummy function for API deployment&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/test&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;any&lt;/span&gt;
          &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As we can see above, we are using &lt;code&gt;provider.deploymentBucket.name&lt;/code&gt; and consuming the exported bucket name from our previous file using &lt;code&gt;${output:${self:app}-shared-bucket-artifacts.S3SharedBucketArtifactsName}&lt;/code&gt;. As mentioned before, &lt;code&gt;${output:...}&lt;/code&gt; is a Serverless Framework Pro feature, but you can do the same with CloudFormation.&lt;/p&gt;

&lt;p&gt;You can check the &lt;a href="https://github.com/serverless-guru/templates/pull/18"&gt;full example in this pull request&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/serverless-guru/templates/pull/18"&gt;https://github.com/serverless-guru/templates/pull/18&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;With a simple change, you can avoid hitting the limits of your AWS account and still benefit from the usage of Serverless Framework.&lt;/p&gt;

&lt;p&gt;Also keeping your Cloud environment and workflow development tidy and neat!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
