Artifacts not working as expected

I have been banging my head against a wall for days trying to get this to work…

We’re trying to deploy a serverless microservice using Azure DevOps CI/CD pipelines, and trying to implement the solution found here: https://medium.com/@bishwash.aryal/serverless-framework-build-immutable-package-for-ci-cd-pipeline-949b49f7df91

I need to be able to create immutable packages to promote through our pipeline, so this seemed to be a good workaround solution.

In my build step, I run serverless package to a folder and then delete the CF templates and state file, leaving only the generated myzipfile.zip. I then copy the serverless.yml and package.json files into that folder and zip the whole thing up into an outer zip file. This gets saved as the immutable artifact for the deployment stage.

Here’s the issue… in the deployment stage, when I extract this outer zip file on the build agent (I’ve also run in a local linux environment as a sanity check and get the same behavior), and try to run this command from the directory containing the serverless.yml, package.json, and myzipfile.zip:

serverless deploy --artifact myzipfile.zip --stage qa --region us-east-2

I get this error:

No matching handler found for 'handler' in '<directory-I'm-currently-in>'. Check your service definition.

Here’s my serverless.yml file (with some names changed for security reasons):

service:
  name: my-service
  
package:
  artifact: ${opt:artifact, ""}

# Add the serverless-webpack plugin
plugins:
  - serverless-webpack
  - serverless-offline
  - serverless-domain-manager

custom:
  stage: ${opt:stage, self:provider.stage}
  domains:
    prod: my-prod-domain.com
    qa: my-qa-domain.com
    dev: my-dev-domain.com
  serverless-offline: ## add this two lines
    port: 4000 ## bellow "custom:" line
  
  customDomain:
    domainName: ${self:custom.domains.${self:custom.stage}}
    basePath: 'my-basebath' # This will be prefixed to all routes
    stage: ${self:custom.stage}
    createRoute53Record: true
  

provider:
  name: aws
  runtime: nodejs8.10
    
functions:
  GetSomething:
    handler: handler.GetSomething
    events:
      - http:
          method: get
          path: /{search_string}
          cors: true
  
  GetAllSomethings:
    handler: handler.GetAllSomethings
    events:
      - http:
          method: get
          path: /
          cors: true

I cannot figure out what the problem is. According to the documentation I’d expect the underlying serverless package to use the zip file I gave it, and not attempt to look for a source file… It seems like it’s trying to resolve the handler by looking for a file called handler in the directory, when handler.js is inside the myzipfile.zip file.

Can someone please help me with this?

Thanks!

Matt

I think you need to use –package option. I don’t think serveless support –artifact option. See this instruction https://serverless.com/framework/docs/providers/aws/guide/packaging/

You could try the command seed.run service uses:
serverless package --stage dev --package stage-artifacts

I haven’t found a way to do truly immutable deployments with serverless unless your deploy is static for a given AWS account in a given Region. I don’t see any way to be able to say something like serverless deploy --package ./serverless/stuff --stage qa --region us-west-2.

I’ve found that I can make a package that is now 100% locked to the specific region, stage and all environment variables used at the time serverless package was run. Which does not make this very useful in CICD pipeline since this is only deployable to one place if I use any environment vars to help configure the deployment.

Using SSM settings is fine, just completely locks this specific packaing to a single deployment into a single stage, single region, single AWS Account deployment.

Anyone find a better way?