Using Docker Compose for React Storybook Development
So here's the situation. We have a single Docker container for our Gatsby-based project. We have this hooked up to AWS Amplify for CI/CD. It's looking pretty, here's the Dockerfile
#
# Create the installation layer
FROM node:12.7.0-alpine as install
WORKDIR /usr/app
# Install Dependencies
COPY ./package.json ./package-lock.json ./
RUN npm i --silent
#
# Create the application development layer
FROM node:12.7.0-alpine as develop
# Expose Ports
EXPOSE 8000
# Create and change into a directory in the container
WORKDIR /usr/app
COPY --from=install /usr/app/. .
COPY . .
#
# @TODO: Create the testing layer
# A container build should fail here if tests fail
# RUN npm test or static analysis, linting, whatever
#
# @TODO: Create the production build layer
# This should only result in production npm deps installed
FROM node:12.7.0-alpine as production
WORKDIR /usr/app
# Install prod deps
COPY ./package.json ./package-lock.json ./
RUN npm i --production --silent
# Copy code from... somewhere
COPY . .
# Run a gatsby build production
RUN npm run build
# Should just be static files (HTML, JS, CSS, Media assets)
# For later copying
#
# Create the file serving layer (scratch image)
# This should end up with only static files in a file system
# With no actual operating system or binaries
FROM scratch
WORKDIR /build
COPY --from=production /usr/app/public .
# We now should have a directory called public
# With only static files (HTML, JS, CSS, Media assets)
# Default Command - This is never used
CMD [""]
And here is our Docker Compose file to make it super easy to spin up, tear down, rebuild with a command like docker-compose up
. It's amazing! Wanna do it in the background, throw in a -d
at the end. Need to totally rebuild it? Add a dash of that --build
flag. It's fantastics.
```yml
version: "3.7"
services:
heroines-site:
build:
context: ./public-site
target: develop
image: heroines-site
container_name: heroines-site
init: true
command: npm run develop -- -H 0.0.0.0
ports:
- 8000:8000
volumes:
- /usr/app/node_modules
- ./public-site:/usr/app
This is perfect. It does just what we want, creates a pretty slim image for local. AWS Amplify also builds this from a master-commit, and builds it inside a consistent Docker build container. So we're good!
Okay, so, we have a local build of Gatsby running on localhost:8000/
. We get access to the GraphQL endpoint at localhost:8000/__graphql
as well.
What if we wanted to run a parallel container that ran React Storybook? Well that's a different port, and a different concern. We 100% don't want to try to run this in production, but we want that for local development. Trust me, it's very nice.
So we make another container. Consider this a sidecar container
pattern. It looks like this:
version: "3.7"
services:
heroines-site:
build:
context: ./public-site
target: develop
image: heroines-site
container_name: heroines-site
init: true
command: npm run develop -- -H 0.0.0.0
ports:
- 8000:8000
volumes:
- /usr/app/node_modules
- ./public-site:/usr/app
heroines-storybook:
build:
context: ./public-site
target: develop
image: heroines-storybook
container_name: heroines-storybook
init: true
command: npm run storybook
ports:
- 6006:6006
volumes:
- /usr/app/node_modules
- ./public-site:/usr/app
So we have a whole separate container we can bring up, different than the Gatsby container. The command would look like docker-compose up heroines-storybook
and you will get one running container with storybook, exposing only port 6006
If you wanted to bring up the whole stack (2 containers) you would use the same familiar command of docker-compose up
, and as you can guess, if you only want to bring up the Gatsby site, with no storybook, you can use docker-compose up heroines-site