Using dev container with Redwood

Has anyone had any luck with running Redwood using Docker and dev containers?

Context:
I got a new computer and wanted to see if I could could setup Redwood and have a solid development environment all self-contained in docker.

Using the default Node app template in VSCode and exposing the :8910 and :8911 gets me 90% there.

Current Blocker:
The web app is unable to talk with the api, the proxy that is handled by Webpack Dev Server behind the scenes doesn’t seem to work as expected within Docker, requests to that should be forwarded to the api aren’t but both web and api are accessible individually.

Has anyone successfully got this working?

Hi @Darth-Knoppix! Welcome to the forums :wave:

Have you seen this previous topic on the subject? Running in Docker - #7 by nerdstep Anything in there that helps at all?

1 Like

Are they not forwarded at all, or are they forwarded to the wrong url? (what url in that case?)

Thanks for such a quick reply!

I had a look at the post you mentioned and it helped a bit but the proxying issue seemed to be solved with Nginx. (My Nginx knowledge is limited)

Requests from the web app are hitting this url, http://localhost:8910/.netlify/functions/graphql and aren’t being forwarded to the backend api.

I’ll try tinkering with config and Nginx as a last resort and share where I get to.

localhost inside docker or on your own machine?

I’m using localhost:8910 on my host machine to access the web frontend. It’s accessible as is localhost:8911 but when I request a page that performs a fetch to the API, it fails.

This is being served by the yarn rw dev command within a container, for reference here is the config I’m using Redwood Dev Container · GitHub

This is what the browser request looks like:

URL: http://localhost:8910/.redwood/functions/graphql
Status: 500 Internal Server Error
Source: Network
Address: ::1:8910

The response from the dev server is [HPM] Error occurred while trying to proxy request /graphql from localhost:8910 to http://[::1]:8911 (EADDRNOTAVAIL) (https://nodejs.org/api/errors.html#errors_common_system_errors)

The address http://[::1]:8911 is also accessible on my host.

I’ve used docker like once five years ago. So I’m sorry, but I can’t help you any further. @jeliasson Do you have any ideas?

1 Like

I run RedwoodJS with Docker images in production but not for the development workflow. When it comes to the proxying part, I submitted a issue along with a PR to extend the @redwoodjs/api-server package with a routePrefix option. See the issue for the motivation behind that. After that I set the apiProxyPath to "/api" in redwood.toml. Now I proxy / to web containers and /api to the api containers.

I think you’re already set with the Dockerfiles, but here is what I do for production.

api/Dockerfile

###################################################################################################################
# Runner: node
###################################################################################################################

FROM node:12 as runner

# Node
ARG NODE_ENV
ARG RUNTIME_ENV

ENV NODE_ENV=$NODE_ENV
ENV RUNTIME_ENV=$RUNTIME_ENV

ARG DATABASE_URL
ENV DATABASE_URL=$DATABASE_URL

# Set workdir
WORKDIR /app

COPY api api
COPY .nvmrc .
COPY babel.config.js .
COPY graphql.config.js .
COPY package.json .
COPY redwood.toml .
COPY yarn.lock .

# Debug
RUN date

# Install dependencies
RUN yarn install --frozen-lockfile

# Build
RUN yarn rw build api

# Migrate database
RUN yarn rw db up --no-db-client --auto-approve

# Seed database
RUN yarn rw db seed

# Clean up
RUN rm -rf ./api/src

# Set api as workdirectory
WORKDIR /app/api

# Expose RedwoodJS api port
EXPOSE 8911

# Entrypoint to @redwoodjs/api-server binary
ENTRYPOINT [ "yarn", "api-server", "--functions", "./dist/functions", "--port", "8911", "--routePrefix", "/api" ]

web/Dockerfile

###################################################################################################################
# Builder: node
###################################################################################################################

FROM node:12 as builder

# Node
ARG NODE_ENV
ARG RUNTIME_ENV

ENV NODE_ENV=$NODE_ENV
ENV RUNTIME_ENV=$RUNTIME_ENV

# Application specific (Azure Active Directory authentication)
ARG AZURE_ACTIVE_DIRECTORY_CLIENT_ID
ARG AZURE_ACTIVE_DIRECTORY_AUTHORITY
ARG AZURE_ACTIVE_DIRECTORY_REDIRECT_URI
ARG AZURE_ACTIVE_DIRECTORY_LOGOUT_REDIRECT_URI

ENV AZURE_ACTIVE_DIRECTORY_CLIENT_ID=$AZURE_ACTIVE_DIRECTORY_CLIENT_ID
ENV AZURE_ACTIVE_DIRECTORY_AUTHORITY=$AZURE_ACTIVE_DIRECTORY_AUTHORITY
ENV AZURE_ACTIVE_DIRECTORY_REDIRECT_URI=$AZURE_ACTIVE_DIRECTORY_REDIRECT_URI
ENV AZURE_ACTIVE_DIRECTORY_LOGOUT_REDIRECT_URI=$AZURE_ACTIVE_DIRECTORY_LOGOUT_REDIRECT_URIv

# Set workdir
WORKDIR /app

#COPY api .
COPY web web
COPY .nvmrc .
COPY babel.config.js .
COPY graphql.config.js .
COPY package.json .
COPY redwood.toml .
COPY yarn.lock .

# Install dependencies
RUN yarn install --frozen-lockfile

# Build
RUN yarn rw build web

# Clean up
RUN rm -rf ./web/src

###################################################################################################################
# Runner: Nginx
###################################################################################################################

FROM nginx as runner

# Copy dist
COPY --from=builder /app/web/dist /usr/share/nginx/html

# Copy nginx configuration
COPY web/config/nginx/default.conf /etc/nginx/conf.d/default.conf

# List files
RUN ls -lA /usr/share/nginx/html

# Expose RedwoodJS web port
EXPOSE 8910

web/config/nginx/default.conf

server {
    listen 8910 default_server;
    root /usr/share/nginx/html;
    location / {
        try_files $uri $uri/ /index.html;
    }
}

I run my workload in Kubernetes, so below is just a reference to the proxying part.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: app
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt"
spec:
  tls:
    - hosts:
        - example.com
      secretName: example-tls
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            backend:
              serviceName: web
              servicePort: 8910
          - path: /api
            backend:
              serviceName: api
              servicePort: 8911

Hope this helps, and let me know if you want the remaining Kubernetes (and Kustomize) files.

1 Like

Thanks for your help @Tobbe and @jeliasson, It looks like Nginx is the only way to get this working as expected. I think I’ll sideline this for now. I may revisit this when I have a better grasp of how Nginx and dev containers work with multiple services.

I’m a little late to the party @Darth-Knoppix but I think you need to get a bit fancier with how you setup Webpack to handle ports and hosts. Something like the topics in this Issue might do the trick:

Hope there’s something helping in the thread :crossed_fingers:

1 Like