Search code examples
amazon-web-servicesdevopsaws-serverlessserverless-stack

SST: Deploy only some stacks


Here out IaC project structure:

./
├── cdk.context.json
├── package.json
├── package-lock.json
├── README.md
├── sst.json
└── stacks
    ├── common
    │   ├── Msk.js
    │   └── Vpc.js
    ├── index.js
    ├── posiciones
    │   ├── Consumer.js
    │   └── DocumentDB.js
    └── vistas
        ├── Api.js
        └── Database.js

sst.json is:

{
  "name": "rmo-serverless",
  "region": "us-west-2",
  "main": "stacks/index.js"
}

and stacks/index.js:

import { App } from "@serverless-stack/resources";

import { Api } from "./vistas/Api";
import { Database } from "./vistas/Database";
import { Vpc } from "./common/Vpc";
import { Msk } from "./common/Msk";
import { Consumer } from "./posiciones/Consumer";
import { DocumentDB } from "./posiciones/DocumentDB";


/**
 * @param {App} app
 */
export default function (app) {
  app.setDefaultFunctionProps({   //not needed
    runtime: "nodejs14.x",
  });
  app.stack(Vpc)
     .stack(Msk)
     .stack(Database)
     .stack(DocumentDB)
     .stack(Consumer)
     .stack(Api);
}

As I mentioned above, we're infrastructure code (sst) and services code (lambdas), in different repositories.

Currently, we're creating our pipelines. In short, we have two pipelines:

  • 1 pipeline to Deploy indrastructure: documentdb, rds, msk, vpc
  • N pipeline (1 for each) services: lambdas and api gateway

What we are trying to get is that when a service code is pushed on branch, it only re-deploy services related elements, lambdas...

Problem here, is how could we only deploy infrastructure items (documentdb, rds, msk, vpc)? Or how could we deploy only service items (lambdas, api)?

Any suggestions in order to best organize sst project?


Solution

  • One suggestion is to utilize your stage names. For example, you may have a helper function like this in let's say /utils/index.ts:

    /**
     * A conditional helper function, add Stack based on given `stage` name.
     *
     * @param {App} app
     * @param {string} stage
     * @param {any} stack
     * @returns void
     */
    export const addStackPerStage = (app, stage, stack) => {
      if (app.stage === stage) {
        app.stack(stack);
      }
    };
    

    Then using this helper function like below:

    import { App } from "@serverless-stack/resources";
    
    import { Api } from "./vistas/Api";
    import { Database } from "./vistas/Database";
    import { Vpc } from "./common/Vpc";
    import { Msk } from "./common/Msk";
    import { Consumer } from "./posiciones/Consumer";
    import { DocumentDB } from "./posiciones/DocumentDB";
    import { addStackPerStage } from "./utils";
    
    /**
     * @param {App} app
     */
    export default function (app) {
      app.setDefaultFunctionProps({   //not needed
        runtime: "nodejs14.x",
      });
      
      // Infrastructure ONLY.
      addStackPerStage(app, "infrastructure-only", Vpc);
      addStackPerStage(app, "infrastructure-only", Msk);
      addStackPerStage(app, "infrastructure-only", Database);
      addStackPerStage(app, "infrastructure-only", DocumentDB);
    
      // Service 1 Only
      addStackPerStage(app, "service-1-only", Consumer); // use vpc.fromLookup instead
      
      // Service 2 Only
      addStackPerStage(app, "service-2-only", Api); // use vpc.fromLookup instead
    }
    

    Then, your script may be used like:

    sst deploy --stage=infrastructure-only
    

    And about branch names, you may utilize a npm package like https://www.npmjs.com/package/branch-name. Then, refactor the suggested codebase above, to use 'branch names' instead, as your new 'flag' to conditionally 'append Stack(s)'.

    Lastly, I'm answering the best I can based on paragraphs below:

    What we are trying to get is that when a service code is pushed on branch, it only re-deploy services related elements, lambdas...
    
    Problem here, is how could we only deploy infrastructure items (documentdb, rds, msk, vpc)? Or how could we deploy only service items (lambdas, api)?
    

    I hope this suggestion helps. As on my end, I use this helper function in the case of Organisational Units and N AWS accounts per OU, also with Resource Access Manager (RAM) etc.

    Bonus: I just found out about Stack Sets this week, take a look here if this Construct interests you, https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudformation.CfnStackSet.html. Ideal if you're deploying Stacks by AWS Accounts as well.