serverless remove in my CI/CD pipeline results in this error:
Error: Cannot find module '/root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component'
The remove job results in:
459$ serverless remove
460 0s › Components › Running .
461aNA
462 0s › Template › Removing .
463aNA
464 error:
465 Error: Cannot find module '/root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component'
466Require stack:
467- /usr/local/lib/node_modules/serverless/node_modules/@serverless/core/src/Component.js
468- /usr/local/lib/node_modules/serverless/node_modules/@serverless/core/src/index.js
469- /usr/local/lib/node_modules/serverless/node_modules/@serverless/cli/src/index.js
470- /usr/local/lib/node_modules/serverless/bin/serverless.js
471 at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)
472 at Function.Module._load (internal/modules/cjs/loader.js:725:27)
473 at Module.require (internal/modules/cjs/loader.js:952:19)
474 at require (internal/modules/cjs/helpers.js:88:18)
475 at Template.load (/usr/local/lib/node_modules/serverless/node_modules/@serverless/core/src/Component.js:108:24)
476 at async fn (/usr/local/lib/node_modules/serverless/node_modules/@serverless/template/utils.js:309:27)
477 at async Promise.all (index 0)
478 at async syncState (/usr/local/lib/node_modules/serverless/node_modules/@serverless/template/utils.js:333:3)
479 at async Template.remove (/usr/local/lib/node_modules/serverless/node_modules/@serverless/template/serverless.js:78:5)
480 at async Object.runComponents (/usr/local/lib/node_modules/serverless/node_modules/@serverless/cli/src/index.js:218:17) {
481 code: 'MODULE_NOT_FOUND',
482 requireStack: [
483 '/usr/local/lib/node_modules/serverless/node_modules/@serverless/core/src/Component.js',
484 '/usr/local/lib/node_modules/serverless/node_modules/@serverless/core/src/index.js',
485 '/usr/local/lib/node_modules/serverless/node_modules/@serverless/cli/src/index.js',
486 '/usr/local/lib/node_modules/serverless/bin/serverless.js'
487 ]
488}
489 0s › Template › Error: Cannot find module '/root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component'
490Require stack:
491- /usr/local/lib/node_modules/serverless/node_modules/@serverless/core/src/Component.js
492- /usr/local/lib/node_modules/serverless/node_modules/@serverless/core/src/index.js
493- /usr/local/lib/node_modules/serverless/node_modules/@serverless/cli/src/index.js
494- /usr/local/lib/node_modules/serverless/bin/serverless.js
495
Cleaning up file based variables
00:01
496ERROR: Job failed: exit code 1
I can run the exact code locally with sls and sls remove and it provisions and removes as expected.
The sls command correctly provisions in the initial job, but the subsequent remove job fails as per the logs above.
.gitlab-ci-yml
image: node:latest
before_script:
- npm config set prefix /usr/local
- npm install -g serverless
- npm install
- apt-get update && apt-get install -y python3 python3-pip python3-setuptools groff less && pip3 install --upgrade pip && apt-get clean
- pip3 --no-cache-dir install --upgrade awscli
stages:
- Deploy
- Remove
Deploy Staging:
stage: Deploy
environment: staging
variables:
SLS_NEXT_S3_STATE_BUCKET: my-state-bucket-staging
script:
- echo "Deploy Staging"
- aws s3 sync s3://$SLS_NEXT_S3_STATE_BUCKET/.serverless .serverless --delete
- serverless
- aws s3 sync .serverless s3://$SLS_NEXT_S3_STATE_BUCKET/.serverless --delete
rules:
- if: $CI_COMMIT_BRANCH == "master" && $CI_PIPELINE_SOURCE != "schedule"
Remove Staging:
stage: Remove
environment: staging
variables:
SLS_NEXT_S3_STATE_BUCKET: my-state-bucket-staging
script:
- echo "Remove Staging"
- aws s3 sync s3://$SLS_NEXT_S3_STATE_BUCKET/.serverless .serverless --delete
- serverless remove
- aws s3 rm s3://$SLS_NEXT_S3_STATE_BUCKET --recursive
rules:
- if: $CI_COMMIT_BRANCH == "master" && $CI_PIPELINE_SOURCE != "schedule"
when: manual
serverless.yml (Note: I've removed the env variables below from the gitlab-ci.yml above for simplification
org: ${env.SLS_NEXT_ORG}
app: ${env.SLS_NEXT_APP}
name: ${env.SLS_NEXT_NAME}
stage: ${env.SLS_NEXT_STAGE}
domain: ${env.SLS_NEXT_DOMAIN}
fullDomain: '${subdomainStage.${stage}}${domain}'
subdomainStage:
prod: ''
staging: staging.
dev: dev.
distribution: ${env.SLS_NEXT_DISTRIBUTION_MAIN}
bucketName: ${env.SLS_NEXT_BUCKET_NAME}
next-sls-app:
component: '@sls-next/[email protected]'
inputs:
cloudfront:
distributionId: ${distribution}
priceClass: 'PriceClass_100'
aliases: ['${fullDomain}']
bucketName: ${bucketName}
bucketRegion: 'eu-west-1'
description: 'Lambda@Edge for ${org}-${app}-${name}-${stage}'
name:
defaultLambda: ${org}-${app}-${name}-${stage}-default
apiLambda: ${org}-${app}-${name}-${stage}-api
runtime:
defaultLambda: 'nodejs12.x'
apiLambda: 'nodejs12.x'
package.json (Note: I've tried all combinations of serverless being installed as dependency, and globally as per gitlab-ci.yml above, so here is an example of a local dependency)
{
"name": "app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"mysql": "^2.18.1",
"next": "9.5.4",
"next-auth": "^3.1.0",
"react": "16.13.1",
"react-dom": "16.13.1"
},
"devDependencies": {
"serverless": "^2.8.0"
}
}
As above
I have pinned the version in my serverless.yml, as per the README and I've reviewed all of the issues similar that I could find - most of which had issues with the deploy sls and not pinning versions. This one is similar, but definitely different in that I'm attempting to use sls remove and this is where the failure occurs. This issue existed in version 1.18.0-alpha.12 also; I upgraded and tested locally and through GitLab-CI before posting this, and the same results.
Also, I've reviewed the .serverless templates generated for the local environment and the s3 bucket state environment and they look the same (apart from stage and aws resources). The Template.json is as follows:
{
"components": {
"next-sls-app": "/root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component"
}
}
It seems this is what is being looked at by the GitLab CI runner and cannot find it in the environment
im seeing this as well. i was on 1.17 which just broke randomly. tried 1.18 alpha and getting the same error. also downgraded to 1.16 and getting the same error as well
I’m now seeing this even on my deploy stage too. I have gone back as far as alpha.12 and I’m getting all sorts of similar errors
I’ve even reverted my original working master branch and that has stopped working
Sorry, I am not as familiar with the remove command but this is strange. Just for sanity, checked that @1.18.0-alpha.18 is published correctly to npm and I am able to install locally.
Could you please check what is the contents of root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/?
This line seems strange:
Error: Cannot find module '/root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component'
I don't know why it is trying to load a nested @sls-next/serverless-component, it should loaded at the top level from dist/component.js. I checked /root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/ node and it should only be aws-cloudfront, aws-lambda, cloudfront, domain, lambda-at-edge, next-aws-cloudfront, s3-static-assets (those are internal dependencies).
I wonder if this could be issue with serverless components itself, maybe a recent change broke how serverless components are resolved (and this being on the serverless components beta may not help either). If you are using CI and serverless version is not pinned, since a CI workflow normally uses a clean environment, it would usually download latest version.
@danielcondemarin would you have any ideas?
My experience is the remove command does not remove the CloudFront distribution or lambda function(s). Those need to be removed manually. Here's the steps I use to remove a serverless-nextjs deployed site.
serverless remove from command line.
log in to aws console
navigate to CloudFront and disable the Distribution for the deployed serverless-nextjs component (be sure to select the correct distribution if you have many).
wait about 5 minutes
delete the CloudFront distribution for the deployed serverless-nextjs component (again make sure because there's no going back if you delete an incorrect distribution)
wait about 15 minutes. During this time your CloudFront distribution is deleted from edge locations
Now you can delete the Lambda function(s) created by the serverless-nextjs component. NOTE: If you get an error that the lambda function can not be deleted, you need to wait longer. The time does vary to delete all the CloudFront distributions. I find 15 minutes is an average time. There may be 1 or 2 lambda's -- one for content, one for api.
Just to clarify my earlier comment. I'm seeing this when i run serverless, not serverless remove
I see, I did test with the latest serverless versions (e.g 2.8.0 and 2.7.0) and it seems fine for both commands, both locally and on GitHub actions. Unfortunately I don't use GitLab so I can't help too much there, if someone else uses maybe they can help.
Though as mentioned this line is still strange either way:
Error: Cannot find module '/root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component'
Not sure why it is trying to resolve the path like this, as the end @sls-next/serverless-component doesn't exist for me locally - the component is at top level. Maybe Serverless made an update that's breaking the resolution in certain environments? Perhaps you can try to deploy using an older serverless version. You can do something like:
npx [email protected]
See versions here: https://www.npmjs.com/package/serverless
Unfortunately I can’t do any further tests in the remove command at the moment because the deploy is not working anymore either, for any version of serverless or serverless next
@bhall2001 mentioned that the repo has moved? I’ll try again tomorrow to do some debugging to provide any useful info
Ok, thanks @damo78. I guess I was a bit confused - I thought the issue @bhall2001 mentioned is separate but semi-related issue - it's known the remove command may not work well because the CloudFront distribution takes a long time to disable and delete (this is an AWS bottleneck).
Also, the latest component to use is @sls-next/serverless-component, so I think you have it right there.
Sorry I was mistaken earlier, that @sls-next/serverless-component should exist in the component stored. I was previously looking at npm installation but the Serverless component installation is slightly different: E.g for my local deployment, in Template.json it is here:
"/Users/danielphang/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component"
So I suspect the path here got changed in GitLab, not sure what it would be since I don't use GitLab:
/root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component'
If you can figure what it should be and update it in Template.json, it might help?
I was able to fix this by manually creating the directory before running serverless with: mkdir -p /root/.serverless/components/registry/npm/@sls-next/[email protected]. This obviously isn't a great solution but it should unblock everyone.
The issue seems to be that serverless doesnt create the directory before it tries to install the component and npm install <package> --prefix <dir> fails if <dir> doesnt exist. I think this is a serverless bug.
Thank you for this thread. I was hit by a (probably) related issue.
Since yesterday, I could not deploy anymore through CircleCI.
Deploy from local machine worked just fine, and I was lost why.
For those running into simular problems: I was able to fix by
Copying the directory from the CircleCI build log where it failed.
In my case /home/circleci/.serverless/components/registry/npm/@sls-next/[email protected].
Adding a step in my CircleCI script just before npx serverless deploy step, that does
mkdir - p [directory here].
This fixed the deployment through CI/CD for me.
Thanks everybody for their support on this. I will try out the manual directory creation in the pipeline as temporary fix.
To try answer some of the questions above, here is everything I've tried. Firstly it's worth noting that the deploy stage within GitLab was fully working up until last week on versions of serverless 2.6.0, 2.7.0 and 2.8.0, and also the serverless component 1.18.0-alpha.12, -alpha.16,-alpha.17 and -alpha.18. It was only the remove that wasn't working.
Then something changed and all combinations of the above whether installing serverless globally or locally to the GitLab directory have stopped working with the above "registry" directory error, including using npx. I went down a strand of thought thinking my node_modules caching was causing the problem, but cleared these and still it wasn't working. I then rebuilt the entire project starting from a new repo, various tests on the many versions again and still no luck.
Locally on my Mac it works as expected.
The deploy error on GitLab looks as described by others above, which is pretty much the same as I was getting at the remove stage prior to this happening:
48 $ serverless
49 0s › Components › Running .
50aNA
51 0s › Template › Deploying .
52aNA
53 0s › Template › Deploying ..
54aNA
55 0s › Template › Deploying ..
56aNA
57 0s › Template › Deploying ...
58aNA
59 0s › Template › Deploying ...
60aNA
61 0s › Template › Deploying
62aNA
63 0s › Template › Deploying
64aNA
65 0s › Template › Deploying
66aNA
67 0s › Template › Deploying .
68aNA
69 error:
70 Error: Command failed: npm install @sls-next/[email protected] --prefix /root/.serverless/components/registry/npm/@sls-next/[email protected]
71npm ERR! code ENOENT
72npm ERR! syscall lstat
73npm ERR! path /root/.serverless/components/registry/npm/@sls-next
74npm ERR! errno -2
75npm ERR! enoent ENOENT: no such file or directory, lstat '/root/.serverless/components/registry/npm/@sls-next'
76npm ERR! enoent This is related to npm not being able to find a file.
77npm ERR! enoent
78npm ERR! A complete log of this run can be found in:
79npm ERR! /root/.npm/_logs/2020-10-23T21_48_45_484Z-debug.log
80 at ChildProcess.exithandler (node:child_process:309:12)
81 at ChildProcess.emit (node:events:327:20)
82 at maybeClose (node:internal/child_process:1048:16)
83 at Process.ChildProcess._handle.onexit (node:internal/child_process:288:5) {
84 killed: false,
85 code: 254,
86 signal: null,
87 cmd: 'npm install @sls-next/[email protected] --prefix /root/.serverless/components/registry/npm/@sls-next/[email protected]',
88 stdout: '',
89 stderr: 'npm ERR! code ENOENT\n' +
90 'npm ERR! syscall lstat\n' +
91 'npm ERR! path /root/.serverless/components/registry/npm/@sls-next\n' +
92 'npm ERR! errno -2\n' +
93 "npm ERR! enoent ENOENT: no such file or directory, lstat '/root/.serverless/components/registry/npm/@sls-next'\n" +
94 'npm ERR! enoent This is related to npm not being able to find a file.\n' +
95 'npm ERR! enoent \n' +
96 '\n' +
97 'npm ERR! A complete log of this run can be found in:\n' +
98 'npm ERR! /root/.npm/_logs/2020-10-23T21_48_45_484Z-debug.log\n'
99}
100 0s › Template › Error: Command failed: npm install @sls-next/[email protected] --prefix /root/.serverless/components/registry/npm/@sls-next/[email protected]
101npm ERR! code ENOENT
102npm ERR! syscall lstat
103npm ERR! path /root/.serverless/components/registry/npm/@sls-next
104npm ERR! errno -2
105npm ERR! enoent ENOENT: no such file or directory, lstat '/root/.serverless/components/registry/npm/@sls-next'
106npm ERR! enoent This is related to npm not being able to find a file.
107npm ERR! enoent
108npm ERR! A complete log of this run can be found in:
109npm ERR! /root/.npm/_logs/2020-10-23T21_48_45_484Z-debug.log
111
Cleaning up file based variables
00:00
113ERROR: Job failed: exit code 1
So I suspect the path here got changed in GitLab, not sure what it would be since I don't use GitLab:
/root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component'If you can figure what it should be and update it in
Template.json, it might help?
Thanks for your help @dphang. I had checked the Template.json prior and I get a similar local and on pipeline dir path. The /root/.serverless.... is the GitLab local runner user as you'd find locally on your own machines with /Users/Daniel/etc...
My state was being sent/received from an S3 bucket from the GitLab runner and was also working fine thanks to following @bhall2001 's guide. But as described above, something went pop towards the end of last week
@damo78 I do not use GitLab (CircleCI instead), but the error surely seems like the one I am getting.
Also the behavior is same as mine: deploy from Local works fine, deploy through CI/CD fails.
What you could try: Add a step in your .gitlab-ci-yml.
My guess woulld be in the before_script, just after - npm install
That says:
- mkdir -p /root/.serverless/components/registry/npm/@sls-next/[email protected]
Which is the (missing) directory that cause the fail.
For me this solved it. Hope you have similar luck!
The temporary workaround does work for me so many thanks for getting me past this blocker. Obviously hard-coding this into the pipeline is not great but at least I can move on to the other elements I want to test whilst this gets looked into.
373 Deploy staging
374$ mkdir -p /root/.serverless/components/registry/npm/@sls-next/[email protected]
375$ aws s3 sync s3://$SLS_NEXT_S3_STATE_BUCKET/.serverless .serverless --delete
376$ serverless
377 0s › Components › Running .
378aNA
379 0s › Template › Deploying .
380aNA
381 0s › Template › Deploying ..
382aNA
383 0s › Template › Deploying ..
384aNA
385 0s › Template › Deploying ...
...
2865 next-sls-app:
2866 appUrl: https://randomString-blah.cloudfront.net
2867 bucketName: my-bucket-origin
2868 distributionId: E2LH300EXAMPLE
2869 126s › next-sls-app › done
2870$ aws s3 sync .serverless s3://$SLS_NEXT_S3_STATE_BUCKET/.serverless --delete
I thought I'd see if this solution would work for the remove stage, i.e. creating the "registry" path. My setup uses and existing terraform CloudFront distro and S3 origin bucket, and locally I know I have to delete the S3 contents first otherwise serverless remove doesn't work. It also disables the CloudFront distro, which is quite good rather than deleting it so I can use my terraform to re-enable and keep the same identifiers.
Unfortunately, it didn't work for `remove with the same errors as before. I suspected as such given it was a cannot find module error, rather than directory missing problem.
415$ serverless remove
416 0s › Components › Running .
417aNA
418 0s › Template › Removing .
419aNA
420 error:
421 Error: Cannot find module '/root/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component'
422Require stack:
423- /usr/local/lib/node_modules/serverless/node_modules/@serverless/core/src/Component.js
424- /usr/local/lib/node_modules/serverless/node_modules/@serverless/core/src/index.js
425- /usr/local/lib/node_modules/serverless/node_modules/@serverless/cli/src/index.js
426- /usr/local/lib/node_modules/serverless/bin/serverless.js
...
It's weird how this works locally for me, but not on GitLab's runners. For now, I'll use the manual removal.
Do I need to raise a separate issue for the deploy problem vs. this remove problem? As they've been intertwined and are two very different problems?
I'm facing the same issue when trying to remove a deployment using Circleci. I'm storing the state in S3, deploy works fine, but then when I try to remove it, I get this error:
mkdir -p /home/circleci/.serverless/components/registry/npm/@sls-next/[email protected]
serverless remove
0s › Components › Running .
nfinityA
0s › Template › Removing .
nfinityA
error:
Error: Cannot find module '/home/circleci/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component'
Require stack:
- /snapshot/serverless/node_modules/@serverless/core/src/Component.js
- /snapshot/serverless/node_modules/@serverless/core/src/index.js
- /snapshot/serverless/node_modules/@serverless/cli/src/index.js
- /snapshot/serverless/bin/serverless.js
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:964:15)
at Function.Module._resolveFilename (pkg/prelude/bootstrap.js:1346:46)
at Function.Module._load (internal/modules/cjs/loader.js:840:27)
at Module.require (internal/modules/cjs/loader.js:1024:19)
at Module.require (pkg/prelude/bootstrap.js:1225:31)
at require (internal/modules/cjs/helpers.js:72:18)
at Template.load (/snapshot/serverless/node_modules/@serverless/core/src/Component.js:108:24)
at async fn (/snapshot/serverless/node_modules/@serverless/template/utils.js:309:27)
at async Promise.all (index 0)
at async syncState (/snapshot/serverless/node_modules/@serverless/template/utils.js:333:3) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/snapshot/serverless/node_modules/@serverless/core/src/Component.js',
'/snapshot/serverless/node_modules/@serverless/core/src/index.js',
As you can see, I even tried to solution @wintvelt suggested, the folder is created successfully, but it still fails. It seems like serverless is trying to find the component package and can't find it.
I'm I missing something here?
Seeing this issue as well. This seems to be related https://github.com/serverless-nextjs/serverless-next.js/issues/504? cc @dphang @danielcondemarin
Honestly, I am not quite sure on this as I couldn't reproduce myself locally - so I still think it may be an issue with the serverless framework, maybe a new version from serverless v2 resolves the component npm package differently. If you are deploying in CI, running npx serverless will always use the latest version, since CI generally provisions a new container for each job run unless you are using self hosted CI.
We did not change anything related to component resolution recently.
I would suggest the following:
Sorry for the trouble - I think we are exploring other more flexible IaC options like CDK or CDK for Terraform as serverless generally doesn't manage state as well and anyway we have a lot of custom build/deploy logic we are doing ourselves. Hopefully this will work much better in the future.
@dphang thanks for your reply! Even trying with old versions of serverless, nothing changed. One weird thing I've noticed is if I run serverless before running serverless remove it works fine. It seems like only syncing the .serverless folder from s3 and running serverless remove is not enough.
This doesn't work:
aws s3 sync s3://my-bucket/<< pipeline.parameters.environment >>/.serverless .serverless --delete
npx [email protected] remove
But this does:
aws s3 sync s3://my-bucket/<< pipeline.parameters.environment >>/.serverless .serverless --delete
npx [email protected]
npx [email protected] remove
And it fails with the following:
error:
Error: Cannot find module '/home/circleci/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component'
Require stack:
- /home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/core/src/Component.js
- /home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/core/src/index.js
- /home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/cli/src/index.js
- /home/circleci/.npm/_npx/154/lib/node_modules/serverless/bin/serverless.js
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:893:15)
at Function.Module._load (internal/modules/cjs/loader.js:743:27)
at Module.require (internal/modules/cjs/loader.js:965:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Template.load (/home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/core/src/Component.js:108:24)
at async fn (/home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/template/utils.js:309:27)
at async Promise.all (index 0)
at async syncState (/home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/template/utils.js:333:3)
at async Template.remove (/home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/template/serverless.js:78:5)
at async Object.runComponents (/home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/cli/src/index.js:218:17) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/core/src/Component.js',
'/home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/core/src/index.js',
'/home/circleci/.npm/_npx/154/lib/node_modules/serverless/node_modules/@serverless/cli/src/index.js',
'/home/circleci/.npm/_npx/154/lib/node_modules/serverless/bin/serverless.js'
Any idea? I'll keep it deploying before removing, but it's definitely not ideal. Thanks!
Unfortunately I don't use the remove command myself much, so not sure what's going on. @danielcondemarin maybe you know how the serverless component resolution works?
From my testing the problem is that npx serverless generates/installs components and injects paths into Template.json:
"components": {
"app": "/home/runner/.serverless/components/registry/npm/@sls-next/[email protected]/node_modules/@sls-next/serverless-component"
}
When you are in the CI and you want to cleanup your resources in a different job (e.g. on PR merged/closed) you just want to run npx serverless remove, but this will fail because the components are not being installed before that (this is not an issue if you want to remove them at the end of the same CI job, e.g. after running E2E tests).
Workaround is to call npx serverless again that will install the components followed by npx serverless remove. I would expect npx serverless remove to have the same logic of installing the components/packages if required.
Ah, thanks for that, I guess that makes sense now.
Perhaps another workaround is to cache that directory in Template.json somewhere and then load it before calling serverless remove.
@danielcondemarin I'm not sure if there's a quick fix as it seems the problem is inherent to Serverless. We are planning to explore other proper IaC options, so we may not want to invest too much into fixing the state management issues.
I've tried syncing that folder to S3 as it is done for .serverless but it contains 1000+ (node_modules,...) files and is just takes too long so that is not really feasible.
Perhaps another workaround is to cache that directory in Template.json somewhere and then load it before calling
serverless remove.
I've tried many combinations of caching (and s3 syncing) with GitLab CI:
All result in the same error when trying remove. Are you suggesting another caching option to try?
@danielcondemarin I'm not sure if there's a quick fix as it seems the problem is inherent to Serverless. We are planning to explore other proper IaC options, so we may not want to invest too much into fixing the state management issues.
I haven't wanted to write this, but I tend to agree with how much investment should be given to IaC and state-management in general should be given. I keep reading, and have followed much of the advice, to use terraform (or CDK) to provision and maintain infrastructure. Whilst almighty efforts have been given to try and work around serverless, serverless components general and this serverless next componentry, it feels like there's a combination of reinventing the wheel whilst also trying to merge multiple moving parts.
Before this I was looking to try this; next-aws-lambda-webpack-plugin, to transform the referenced CloudFormation/SAM spec into terraform. But I thought I'd gain the benefits of the serverless framework by using this serverless next component. Having researched further, and especially when I understood that serverless components weren't really the serverless framework as such anymore, I'm now not sure what benefits there are for infrastructure provisioning and maintenance left that isn't better suited elsewhere.
Personally I'd rather this bug went stale if I knew that in the near future I'd be able to utilise terraform (or CDK) end-to-end for IaC provisioning into AWS for Next JS. The semi-manual removal stage is no big deal for me at the moment. Workflow for using terraform with serverless infrastructure is already straight-forward enough to keep them separated and sharing, e.g. using SSM Param Store, or CI/CD pipeline outputs. Trying to wedge something else in-between has taken weeks' worth of effort that I feel could be much simpler architecturally.
Please, please do not take this as anything other than me agreeing with your conclusion on time investment for this bug @dphang. You are all doing outstanding work and I'll be continuing with this componentry for this current project to see how it pans out.
For others who run into this issue and are provisioning their CloudFront and S3 origin buckets via terraform, then you can still utilise a useful removal stage. What I found is that even though I didn't provision versioning on my S3 bucket, serverless creates multiple versions over time which means I could not easily use terraform to remove the infrastructure due to the bucket not being empty, and the simple --recursive deletion doesn't work.
I found this script useful in my serverless 'removal' stage which then allowed me to use my terraform removal stage to complete the infrastructure deletion.
echo '#!/bin/bash' > deleteBucketScript.sh && aws --output text s3api list-object-versions --bucket $SLS_NEXT_BUCKET_NAME | grep -E "^VERSIONS" | awk '{print "aws s3api delete-object --bucket $SLS_NEXT_BUCKET_NAME --key "$4" --version-id "$8";"}' >> deleteBucketScript.sh && . deleteBucketScript.sh; rm -f deleteBucketScript.sh; echo '#!/bin/bash' > deleteBucketScript.sh && aws --output text s3api list-object-versions --bucket $SLS_NEXT_BUCKET_NAME | grep -E "^DELETEMARKERS" | grep -v "null" | awk '{print "aws s3api delete-object --bucket $SLS_NEXT_BUCKET_NAME --key "$3" --version-id "$5";"}' >> deleteBucketScript.sh && . deleteBucketScript.sh; rm -f deleteBucketScript.sh;
@damo78 thanks for your thoughts and feedback. For caching I thought something like this would work (example for GitHub Actions): https://github.com/actions/cache instead of syncing to S3. It zips it the whole directory up and stores it with GitHub, so it's faster than trying to sync many files individually to S3 or zipping it up yourself. Sorry to hear if you have already tried and it did not work.
RE: IaC, yea, I feel that Serverless in general is not really good for complex infra, but if you have simple Lambdas and configuration, it works fine. For example, I use regular Serverless Framework + a couple of plugins for a test API endpoints. After all I think originally it was used since there was just a few parts (e.g single Lambda with the original plugin), and then moved to Serverless Component. Then we also imported domain and aws-cloudfront from Serverless Components and made our own updates to those because the originals weren't maintained anymore.
Infrastructure state management is not as easy as it first appears to be, and we are kinda reinventing the wheel here by managing it ourselves via the AWS SDK (since Serverless components don't provide too much outside of Lambda functions), whereas proper IaC like Terraform/CDK would have already solved that plus probably gives way more flexibility (e.g Terraform allows you to manage state on S3, Terraform, GCP, etc.). It has given me trouble especially when managing certificates, Route53 records. Plus, anytime there are new features e.g on CloudFront we need to implement those additional configuration changes - for example for Brotli support, it needs to use the new caching policy, but we are still using the legacy one. Something like Terraform would already be quickly updated by the community. Plus, it will make it easier to support and manage more platforms besides AWS Lambda@Edge.
I think @danielcondemarin and I are looking to prototype CDK for Terraform as we can leverage TypeScript + all Terraform modules, probably providing the vast Terraform ecosystem + allowing more control by actually writing code to update configuration (vs. static configuration files from Terraform). I personally think it may be quite suited for this component since it needs to programmatically update infrastructure on each deploy - at the very least, uploading Lambda, S3 assets and updating the CloudFront Lambda function associations.
That would be awesome @dphang. I'd not heard that terraform had a CDK until now, so I've spent all night looking into this, as well as Pulumi. It seems the TF CDK is quite some way away from primetime, whereas Pulumi is very mature with a migration path from TF. However, given the size of the TF community and business adoption of TF so far, I suspect the TF CDK is probably going to come out on top. Good luck and thanks again!
@damo78, thanks, yeah it's relatively new (I think released earlier this year?) so we should keep it in mind and also consider Pulumi.
Most helpful comment
I was able to fix this by manually creating the directory before running
serverlesswith:mkdir -p /root/.serverless/components/registry/npm/@sls-next/[email protected]. This obviously isn't a great solution but it should unblock everyone.The issue seems to be that serverless doesnt create the directory before it tries to install the component and
npm install <package> --prefix <dir>fails if<dir>doesnt exist. I think this is a serverless bug.