loading...
Cover image for My Docker Setup For GatsbyJS (and NextJS)

My Docker Setup For GatsbyJS (and NextJS)

stoutlabs profile image Daniel Stout Updated on ・3 min read

Update: Alpine made a couple changes that affect this post, and a helpful comment below will clear up the issue(s) caused from that. Thanks Jonathan! I've also fixed the example code.

Update #2: It seems that Hot Module Reloading is currently borked with this in Windows. I'll post an update if/when that is fixed!

Update #3: If you're still experiencing issues, another comment below might get you back on track: HERE

Docker is Fantastic

I'm probably late to the party on this one, but I recently started using Docker as a part of my development workflow. I absolutely love it, and I feel that all developers should at least tinker with a basic tutorial somewhere. Trust me, it's a rabbit hole worth exploring!

But... There Was a Minor Hitch

While going through a some of my recent Gatsby and NextJS projects this week to "Dockerize" them, I noticed that there didn't seem to be much information readily available for making that happen.

Gatsby does offer a Docker setup within their repo (based on alpine:edge), but to be blunt: it seemed needlessly complicated and vague, and I could not make it work for my purposes. (I think it's only meant to serve a site, post-build.)

So, I decided to figure out how to create a custom one from an official node:alpine (latest) image... just something to use for a quick dev environment setup regardless of which computer I'm using. (If I wanted to deploy somewhere other than Netlify, I could quickly add an Nginx image/service and a super basic conf file.)

Problem Solved!

After hours of learning, research, and experimenting (and possibly some frustration), I present you with my version of a working Dockerfile! It will create a fully functional Docker image that installs all the required packages in Apline Linux (latest) for building Gatsby (and NextJS) sites and apps.

(Note: For NextJS sites, I simply change the final CMD and the port(s) to whatever I'm using for the site/app... usually 8080.)

Dockerfile.dev

FROM node:alpine

# Also exposing VSCode debug ports
EXPOSE 8000 9929 9230

RUN \
  apk add --no-cache python make g++ && \
  apk add vips-dev fftw-dev --update-cache \
  --repository http://dl-3.alpinelinux.org/alpine/edge/community \
  --repository http://dl-3.alpinelinux.org/alpine/edge/main \
  && rm -fR /var/cache/apk/*

RUN npm install -g gatsby-cli

WORKDIR /app
COPY ./package.json .
RUN yarn install && yarn cache clean
COPY . .
CMD ["yarn", "develop", "-H", "0.0.0.0" ]

docker-compose.yml

(Note the setting of GATSBY_WEBPACK_PUBLICPATH - this seemed to fix any HMR issues I was having when editing code.)

version: '3'
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "8000:8000"
      - "9929:9929"
      - "9230:9230"
    volumes:
      - /app/node_modules
      - .:/app
    environment:
      - NODE_ENV=development
      - GATSBY_WEBPACK_PUBLICPATH=/

You'll probably want to throw a .dockerignore file into the project directory too, to ignore things like ./node_modules, ./cache, ./public, any .DS_Store files, etc. (Much like a .gitignore file.)

To run it, from the project's root directory run:

$ docker-compose up --build

After running that, I'm ready to work... whether I'm on my Macbook Pro or on my Windows desktop. Hopefully this helps you too!

Discussion

pic
Editor guide
Collapse
stuckj profile image
Jonathan Stucklen

Just a note for anyone else that reads this and runs into this error:

ERROR: unsatisfiable constraints:
  vips-dev (missing):
    required by: world[vips-dev]

This is because alpine recently moved the vips-dev package from edge/testing to edge/community. See this issue for some context on the sharp repo: github.com/lovell/sharp/issues/1733

To fix it, just change the repo URL in the post above from:
http://dl-3.alpinelinux.org/alpine/edge/testing to http://dl-3.alpinelinux.org/alpine/edge/community.

Also, I had to change the --no-cache in the second apk command to --update-cache as is suggested in one of the referenced PRs off the above issue. So, your full docker RUN command for APK installs would look like this (formatting changed):

RUN apk add --no-cache python make g++ \
 && apk add vips-dev fftw-dev build-base \
        --update-cache \
        --repository https://alpine.global.ssl.fastly.net/alpine/edge/community \
        --repository https://alpine.global.ssl.fastly.net/alpine/edge/main \
 && rm -fR /var/cache/apk/*

Hope that helps someone else. It had me stuck for a while. :-P

In addition, yarn fails for me with the latest node (for alpine or otherwise). So, I also had to change the FROM line to fix it to the latest v8. E.g.,

FROM node:8-alpine
Collapse
ivorsco77 profile image
Ivor Scott

This doesn't work anymore. Also don't use edge, always pin down a stable version.

See more here: gitlab.alpinelinux.org/alpine/apor...

Change to version 3.10.

RUN apk add --no-cache python make g++ \
    && apk add vips-dev fftw-dev build-base \
    --update-cache \
    --repository https://alpine.global.ssl.fastly.net/alpine/v3.10/community \
    --repository https://alpine.global.ssl.fastly.net/alpine/v3.10/main \
    && rm -fR /var/cache/apk/*
Collapse
stoutlabs profile image
Daniel Stout Author

FYI: At the time of writing, Edge was the only option for this... and I really don't have time to keep this updated. Thanks for the heads up, I'll make another note at the top!

Collapse
gustavorglima profile image
Gustavo Lima

Here does not Work! Need to change python to python3. E.g.:

RUN apk add --update --no-cache build-base python3-dev python3 libffi-dev libressl-dev bash git gettext curl \
 && curl -O https://bootstrap.pypa.io/get-pip.py \
 && python3 get-pip.py \
 && pip install --upgrade six awscli awsebcli
Collapse
stoutlabs profile image
Daniel Stout Author

Awesome! Thanks for your super helpful comment, Jonathan! I'll be sure to make a note in the original post to see your comment.

Collapse
nrkirby profile image
Nick Kirby

Thanks for this :D

Collapse
mhausenblas profile image
Michael Hausenblas

Very nice, thanks for putting this together, Daniel! One thing I really do encourage you is to define a USER, see also Node/Docker best practices and for the background canihaznonprivilegedcontainers.info.

Collapse
stoutlabs profile image
Daniel Stout Author

Hi Michael, thanks for the comment!

Would this actually be necessary for use in a local development setup like this? This is definitely not being used for production, by any stretch of imagination.

Collapse
yanlinaung profile image
Yan Lin Aung

Thanks for sharing.
I have tried in ubuntu host and encountered this error.

Building web
Step 1/10 : FROM node:alpine
 ---> 09084e4ff58d
Step 2/10 : EXPOSE 8000 9929 9230
 ---> Using cache
 ---> 12194df00fcb
Step 3/10 : RUN   apk add --no-cache python make g++ &&   apk add vips-dev fftw-dev --no-cache --repository  http://dl-3.alpinelinux.org/alpine/edge/testing --repository http://dl-3.alpinelinux.org/alpine/edge/main &&   rm -fR /var/cache/apk/*
 ---> Using cache
 ---> 936946e189e0
Step 4/10 : RUN npm install -g gatsby-cli yarn
 ---> Using cache
 ---> 50623ae2aed6
Step 5/10 : RUN gatsby --version
 ---> Using cache
 ---> 092ab6af8975
Step 6/10 : WORKDIR /app
 ---> Using cache
 ---> 0f7947e32f24
Step 7/10 : COPY ./package.json .
 ---> Using cache
 ---> b46673afd483
Step 8/10 : RUN yarn install && yarn cache clean
 ---> Using cache
 ---> 6355f4a32eb1
Step 9/10 : COPY . .
 ---> 28cc60e9ffa2
Step 10/10 : ENTRYPOINT ["gatsby", "develop", "-H", "0.0.0.0"]
 ---> Running in e1ffe181301b
Removing intermediate container e1ffe181301b
 ---> deaf62676e11
Successfully built deaf62676e11
Successfully tagged blog-name-blog_web:latest
Recreating blog-name-blog_web_1 ... done
Attaching to blog-name-blog_web_1
web_1  | /bin/sh: lscpu: not found
web_1  | success open and validate gatsby-configs — 0.026 s
web_1  | success load plugins — 0.544 s
web_1  | success onPreInit — 6.206 s
web_1  | success initialize cache — 0.037 s
web_1  | success copy gatsby files — 0.075 s
web_1  | warning gatsby-plugin-feed was initialized in gatsby-config.js without a feeds option.
web_1  | This means that we the plugin will use the internal RSS feed creation, which may not match your use case.
web_1  | This behavior will be removed in the next major release of gatsby-plugin-feed.
web_1  | For more info, check out: https://gatsby.app/adding-rss-feed
web_1  | success onPreBootstrap — 0.071 s
web_1  | success source and transform nodes — 0.087 s
web_1  | success building schema — 0.220 s
web_1  | error gatsby-node.js returned an error
web_1  | 
web_1  | 
web_1  |   GraphQLError: Cannot query field "allMarkdownRemark" on type "Query".
web_1  |   
web_1  |   - new Promise
web_1  |   
web_1  |   - index.js:358 graphqlRunner
web_1  |     [app]/[gatsby]/dist/bootstrap/index.js:358:14
web_1  |   
web_1  |   - gatsby-node.js:8 Object.exports.createPages
web_1  |     /app/gatsby-node.js:8:10
web_1  |   
web_1  |   - api-runner-node.js:202 runAPI
web_1  |     [app]/[gatsby]/dist/utils/api-runner-node.js:202:37
web_1  |   
web_1  |   - api-runner-node.js:340 resolve
web_1  |     [app]/[gatsby]/dist/utils/api-runner-node.js:340:19
web_1  |   
web_1  |   - debuggability.js:313 Promise._execute
web_1  |     [app]/[bluebird]/js/release/debuggability.js:313:9
web_1  |   
web_1  |   - promise.js:483 Promise._resolveFromExecutor
web_1  |     [app]/[bluebird]/js/release/promise.js:483:18
web_1  |   
web_1  |   - promise.js:79 new Promise
web_1  |     [app]/[bluebird]/js/release/promise.js:79:10
web_1  |   
web_1  | 
web_1  | success createPages — 0.117 s
web_1  | success createPagesStatefully — 0.041 s
web_1  | success onPreExtractQueries — 0.002 s
web_1  | success update schema — 0.016 s
web_1  | error GraphQL Error There was an error while compiling your site's GraphQL queries.
web_1  |   Error: RelayParser: Encountered 3 error(s):
web_1  | - Unknown field 'file' on type 'Query'. Source: document `BioQuery` file: `GraphQL request`
web_1  |   
web_1  |   GraphQL request (3:5)
web_1  |   2:   query BioQuery {
web_1  |   3:     avatar: file(absolutePath: { regex: "/profile-pic.jpg/" }) {
web_1  |          ^
web_1  |   4:       childImageSharp {
web_1  |   
web_1  | - Unknown field 'allMarkdownRemark' on type 'Query'. Source: document `appSrcPagesIndexJs2785444898` file: `GraphQL request`
web_1  |   
web_1  |   GraphQL request (8:5)
web_1  |   7:     }
web_1  |   8:     allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
web_1  |          ^
web_1  |   9:       edges {
web_1  |   
web_1  | - Unknown field 'markdownRemark' on type 'Query'. Source: document `BlogPostBySlug` file: `GraphQL request`
web_1  |   
web_1  |   GraphQL request (9:5)
web_1  |    8:     }
web_1  |    9:     markdownRemark(fields: { slug: { eq: $slug } }) {
web_1  |           ^
web_1  |   10:       id
web_1  |   
web_1  |     
web_1  | success extract queries from components — 0.076 s
web_1  | success run graphql queries — 0.016 s — 4/4 268.63 queries/second
web_1  | success write out page data — 0.012 s
web_1  | success write out redirect data — 0.011 s
web_1  | success onPostBootstrap — 0.186 s
web_1  | 
web_1  | info bootstrap finished - 22.567291911 s
web_1  | 
web_1  |  ERROR  Failed to compile with 2 errors6:31:15 AM
web_1  | 
web_1  |  error  in ./src/components/bio.js
web_1  | 
web_1  | Module Error (from ./node_modules/eslint-loader/index.js):
web_1  | 
web_1  | /app/src/components/bio.js
web_1  |   57:5  error  Cannot query field "file" on type "Query". Did you mean "site"?  graphql/template-strings
web_1  | 
web_1  | ✖ 1 problem (1 error, 0 warnings)
web_1  | 
web_1  | 
web_1  |  @ ./src/pages/index.js 10:0-36 36:28-31
web_1  |  @ ./.cache/sync-requires.js
web_1  |  @ ./.cache/app.js
web_1  |  @ multi event-source-polyfill (webpack)-hot-middleware/client.js?path=/__webpack_hmr&reload=true&overlay=false ./.cache/app
web_1  | 
web_1  |  error  in ./src/pages/index.js
web_1  | 
web_1  | Module Error (from ./node_modules/eslint-loader/index.js):
web_1  | 
web_1  | /app/src/pages/index.js
web_1  |   58:5  error  Cannot query field "allMarkdownRemark" on type "Query"  graphql/template-strings
web_1  | 
web_1  | ✖ 1 problem (1 error, 0 warnings)
web_1  | 
web_1  | 
web_1  |  @ ./.cache/sync-requires.js 17:54-88
web_1  |  @ ./.cache/app.js
web_1  |  @ multi event-source-polyfill (webpack)-hot-middleware/client.js?path=/__webpack_hmr&reload=true&overlay=false ./.cache/app
web_1  | 
web_1  | ℹ 「wdm」: Failed to compile.
web_1  | ✖ 「wdm」: 
web_1  | ERROR in ./src/components/bio.js
web_1  | Module Error (from ./node_modules/eslint-loader/index.js):
web_1  | 
web_1  | /app/src/components/bio.js
web_1  |   57:5  error  Cannot query field "file" on type "Query". Did you mean "site"?  graphql/template-strings
web_1  | 
web_1  | ✖ 1 problem (1 error, 0 warnings)
web_1  | 
web_1  |  @ ./src/pages/index.js 10:0-36 36:28-31
web_1  |  @ ./.cache/sync-requires.js
web_1  |  @ ./.cache/app.js
web_1  |  @ multi event-source-polyfill (webpack)-hot-middleware/client.js?path=/__webpack_hmr&reload=true&overlay=false ./.cache/app
web_1  | 
web_1  | ERROR in ./src/pages/index.js
web_1  | Module Error (from ./node_modules/eslint-loader/index.js):
web_1  | 
web_1  | /app/src/pages/index.js
web_1  |   58:5  error  Cannot query field "allMarkdownRemark" on type "Query"  graphql/template-strings
web_1  | 
web_1  | ✖ 1 problem (1 error, 0 warnings)
web_1  | 
web_1  |  @ ./.cache/sync-requires.js 17:54-88
web_1  |  @ ./.cache/app.js
web_1  |  @ multi event-source-polyfill (webpack)-hot-middleware/client.js?path=/__webpack_hmr&reload=true&overlay=false ./.cache/app
Collapse
stoutlabs profile image
Daniel Stout Author

It's hard to say, but it looks like you may not have the gatsby-transformer-remark plugin installed and configured?

Sidenote, possibly relevant: If you add any new packages to your app, you will need to rebuild your image using docker-compose build (or docker-compose up --build)

Collapse
yanlinaung profile image
Yan Lin Aung

Thanks for your reply. It is weired. There is no problem when I run docker-compose up in alpine linux host on VPS. Thanks anyway!

Collapse
mik0s profile image
Konstantin Mironov

Not working for me

Step 4/9 : RUN npm install -g gatsby-cli yarn
 ---> Running in bbc35321dd10
npm WARN deprecated core-js@2.6.11: core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.
/usr/local/bin/gatsby -> /usr/local/lib/node_modules/gatsby-cli/lib/index.js
npm ERR! code EEXIST
npm ERR! syscall symlink
npm ERR! path ../lib/node_modules/yarn/bin/yarn.js
npm ERR! dest /usr/local/bin/yarn
npm ERR! errno -17
npm ERR! EEXIST: file already exists, symlink '../lib/node_modules/yarn/bin/yarn.js' -> '/usr/local/bin/yarn'
npm ERR! File exists: /usr/local/bin/yarn
npm ERR! Remove the existing file and try again, or run npm
npm ERR! with --force to overwrite files recklessly.

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2020-02-11T15_31_08_467Z-debug.log
ERROR: Service 'web' failed to build: The command '/bin/sh -c npm install -g gatsby-cli yarn' returned a non-zero code: 239
Collapse
stoutlabs profile image
Daniel Stout Author

Hey Konstantin!

Thanks for the message. It looks like they are now including Yarn with the lastest versions of Alpine:Node, and it's throwing an error trying to re-install it. I'll get it corrected in just a moment or two. 💜

Collapse
mik0s profile image
Thread Thread
daniboy2060 profile image
Dani Boy

How you resolve this error?

Collapse
daniboy2060 profile image
Dani Boy

How you resolve this error?

Collapse
codefull profile image
Ernesto de la Cruz Guevara Ramírez

Hi, Here the configuration that worked for me.

FROM node:12.18.2-alpine3.12

# Install PM2 globally
RUN npm install --global pm2

#Install Gatsby CLI
RUN npm install -g gatsby-cli

RUN mkdir /app
WORKDIR /app
RUN chmod -R 777 /app

# Add node_modules to the path
ENV PATH /app/node_modules/.bin:$PATH

# Installing dependencies
COPY package*.json /app/
RUN cd /app/

RUN npm install

COPY . /app/

# Building app
RUN npm run build



# Run container as non-root (unprivileged) user
# The node user is provided in the Node.js Alpine base image
USER node

EXPOSE 8000

# Run npm start script with PM2 when container starts
CMD [ "pm2-runtime", "npm", "--", "serve" ]
Enter fullscreen mode Exit fullscreen mode

Then "serve" in package.json goes like this .

{
...
"scripts": {
...
serve: "gatsby serve -H 0.0.0.0 -p 8000",
...
},
...
}
Enter fullscreen mode Exit fullscreen mode
Collapse
fwahlqvist profile image
Fredrik Wahlqvist

Hey Ernesto et all thanks for sharing,
When trying to run this i get stuck with the following error

"Recreating frontend_web_1 ... done
Attaching to frontend_web_1
web_1 | 2020-11-14T02:58:15: PM2 log: Launching in no daemon mode
web_1 | 2020-11-14T02:58:15: PM2 log: App [npm:0] starting in -fork mode-
web_1 | 2020-11-14T02:58:15: PM2 log: App [npm:0] online
web_1 | Usage: npm
web_1 | where is one of:"

that repeats itself until i get
"web_1 | 2020-11-14T02:58:24: PM2 log: App [npm:0] exited with code [1] via signal [SIGINT]
web_1 | 2020-11-14T02:58:24: PM2 log: Script /usr/local/bin/npm had too many unstable restarts (16). Stopped. "errored"
web_1 | 2020-11-14T02:58:25: PM2 log: 0 application online, retry = 3
web_1 | 2020-11-14T02:58:27: PM2 log: 0 application online, retry = 2
web_1 | 2020-11-14T02:58:29: PM2 log: 0 application online, retry = 1
web_1 | 2020-11-14T02:58:31: PM2 log: 0 application online, retry = 0
web_1 | 2020-11-14T02:58:31: PM2 log: Stopping app:npm id:0
web_1 | 2020-11-14T02:58:31: PM2 error: app=npm id=0 does not have a pid
web_1 | 2020-11-14T02:58:31: PM2 log: PM2 successfully stopped"

Any ideas?
Many thanks

Collapse
miksdigital profile image
Mikhail

Hi Daniel!
Thanks for sharing!

I just copy-pasted all two files , run docker-compose -up build
and got the error:

Step 6/9 : COPY ./package.json .
ERROR: Service 'web' failed to build: COPY failed: stat /var/snap/docker/common/var-lib-docker/tmp/docker-builder603792599/package.json: no such file or directory

After this message installation stopped.

May be you have an idea how to fix?

Collapse
stoutlabs profile image
Daniel Stout Author

Based on that error, it looks like there was no package.json file found.

Do you have the Dockerfile and docker-compose.yml files in the root of your Gatsby project directory?

Collapse
nrkirby profile image
Nick Kirby

Great post, thanks.

What's the command to run it?

Collapse
stoutlabs profile image
Daniel Stout Author

No prob, Nick! Yeah, the code highlighting on this site isn't very visible, I know... you'll want to run: docker-compose up (from your project's root directory) :)

Collapse
premdasvm profile image
Premdas Vm

So can i use vscode to code in gatsby without installing gastby globally on my local machine?