DEV Community

Docker, Django, React: Building Assets and Deploying to Heroku

Craig Franklin on June 02, 2019

Part 2 in a series on combining Docker, Django, and React. This builds on the development setup from Part 1, so you might want to take a look at th...
Collapse
 
rschuetzler profile image
Ryan Schuetzler • Edited

Thanks for these posts. Using these, I was finally able to figure out how to get Django and my create-react-app frontend working together from the same repo. One tip, using a multi-stage build for the production Dockerfile saves you from having to install Node in the container. This is what I have at the top of mine:

FROM node:lts as build-deps
WORKDIR /frontend
COPY ./frontend/package.json ./frontend/yarn.lock ./
RUN yarn
COPY ./frontend /frontend
RUN yarn build

FROM python:3.6
...

Then where you copy in the files, I have this:

...
COPY . .
COPY --from=build-deps /frontend/build /app/frontend/build

WORKDIR /app/frontend/build
RUN mkdir root && mv *.ico *.js *.json root
RUN mkdir /app/staticfiles

WORKDIR /app
...

This helps keep the Docker image for production as small as you can.

Collapse
 
mrcoles profile image
Peter Coles

Multi-stage builds are great. I did that for a similar project to this but one that dockerizes an express + create-react-app application: github.com/mrcoles/node-react-dock...

# Setup and build the client

FROM node:9.4.0-alpine as client

WORKDIR /usr/app/client/
COPY client/package*.json ./
RUN npm install -qy
COPY client/ ./
RUN npm run build


# Setup the server

FROM node:9.4.0-alpine

WORKDIR /usr/app/
COPY --from=client /usr/app/client/build/ ./client/build/

WORKDIR /usr/app/server/
COPY server/package*.json ./
RUN npm install -qy
COPY server/ ./

ENV PORT 8000

EXPOSE 8000

CMD ["npm", "start"]
Collapse
 
hahnsangkim profile image
H. Kim

Hi Craig

Thank you for the document for deployment. I followed your guide and almost completed it. But I got this error in the end. I wonder you may have gone through it before; do you have any ideas about what's wrong with it? I did 'heroku stack:set container'. Does this create a conflict?

$ git push heroku master
remote: Or change your stack by running: 'heroku stack:set heroku-18'
remote: Verifying deploy...
remote: 
remote: !   Push rejected to vast-escarpment-xxxx.
remote: 
To https://git.heroku.com/vast-escarpment-xxxx.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/vast-escarpment-xxxx.git'

If I switch to heroku-18, heroku doesn't recognize what lang to be used.

remote:  !     No default language could be detected for this app.
remote:             HINT: This occurs when Heroku cannot detect the buildpack to use for this application automatically.
remote:             See https://devcenter.heroku.com/articles/buildpacks
remote: 
remote:  !     Push failed
remote: Verifying deploy...
remote: 
remote: !   Push rejected to vast-escarpment-xxxx.
remote: 
To https://git.heroku.com/vast-escarpment-xxxx.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/vast-escarpment-xxxx.git'

Your two cents will help me out.
I look forward to your feedback~
Best

Collapse
 
hahnsangkim profile image
H. Kim

I narrowed down to the more specific issue. Do you happen to know what key is it expecting? Is it SECRET_KEY? I set it as an environment variable in the heroku setting.

When I push to the heroku git repository, heroku.yml is loaded first, isn't it? I wonder what key is included where...

Hope my question/issue is explanatory...

MacBook-Pro$ git push heroku master
Enumerating objects: 20, done.
Counting objects: 100% (20/20), done.
Delta compression using up to 4 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (14/14), 2.27 KiB | 2.27 MiB/s, done.
Total 14 (delta 5), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: === Fetching app code
remote: 
remote: =!= Build failed due to an error:
remote: 
remote: =!= validate step: error converting YAML to JSON: yaml: line 3: did not find expected key
remote: 
remote: If this persists, please contact us at https://help.heroku.com/.
remote: Verifying deploy...
remote: 
remote: !   Push rejected to vast-escarpment-xxxx.
remote: 
To https://git.heroku.com/vast-escarpment-xxxx.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/vast-escarpment-xxxx.git'
Collapse
 
englishcraig profile image
Craig Franklin • Edited

Based on the message:
validate step: error converting YAML to JSON: yaml: line 3: did not find expected key
I'm guessing that your heroku.yml file is invalid, and the parser isn't able to work out the necessary key/value pairs. Check the first few lines of heroku.yml to make sure everything has the correct syntax. If you're using the exact same heroku.yml from my repo, then my code might be out of date.

Thread Thread
 
hahnsangkim profile image
H. Kim

Thank you so much for your reply, Graig!
It was about an indent error. Now, I have another issue.
Is it about a space issue on the Dyno? or an installation error? It seems relevant to a kind of generic troubleshoot... but if you could look at it and give me your first thought, it will be helpful. Even if not, it will be OK.

Thank you and I look forward to your feedback.
Best,

remote: After this operation, 30.4 MB of additional disk space will be used.
remote: Do you want to continue? [Y/n] Abort.
remote: The command '/bin/sh -c apt-get -y install curl   && curl -sL https://deb.nodesource.com/setup_8.x | bash   && apt-get install nodejs   && curl -o- -L https://yarnpkg.com/install.sh | bash' returned a non-zero code: 1
remote: 
remote: Verifying deploy...
remote: 
remote: !   Push rejected to vast-escarpment-xxxx.
remote: 
To https://git.heroku.com/vast-escarpment-xxxx.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/vast-escarpment-xxxx.git'
Thread Thread
 
hahnsangkim profile image
H. Kim • Edited

I figured it out. V8 of nodejs has been deprecated. I changed the version in Dockerfile

RUN apt-get -y install curl \
  && curl -sL https://deb.nodesource.com/setup_8.x | bash \
  && apt-get install nodejs \
  && curl -o- -L https://yarnpkg.com/install.sh | bash 

into

RUN apt-get -y install curl \
  && curl -sL https://deb.nodesource.com/setup_12.x | bash \
  && apt-get install nodejs \
  && curl -o- -L https://yarnpkg.com/install.sh | bash

I hope this will help others who may give it a try.

Most of all, thank you for your posting and feedback to my questions, Craig!

Collapse
 
oieddyoj profile image
oi-eddyoj

@ Craig, your code only runs Python, not React in the same container?
Nor is there an 'npm start' in your heroku .yml file. How are you running the React code?

Collapse
 
englishcraig profile image
Craig Franklin

Instead of running a separate Webpack server to send the React code to the browser, we build the React code into an optimised code bundle in the Dockerfile. The Django server can then send the React code files to the browser via WhiteNoise. So, we only need the one container/process for the Django server.

Collapse
 
eddyojb profile image
eddy-ojb

With some tweaks I have successfully deployed this on Azure. Thanks Craig.

Collapse
 
eddyojb profile image
eddy-ojb

That sounds amazing. I'll try it out.