React, Django, and PostgreSQL Dockerized — Part 1: Development Setup
Tags: docker, django, react
Published: 2020-07-05 00:00:00

---
title: "React, Django, and PostgreSQL Dockerized — Part 1: Development Setup"
date: "2020-07-05"
lastmod: "2020-07-05"
draft: false
tags: ["docker", "django", "react"]
categories: ["DevOps", "Containers"]
toc: true
summary: "First entry on a series of articles about containerizing a web application."
published: true
cover_image: "https://images.unsplash.com/photo-1568430462989-44163eb1752f?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60"
canonical_url: "https://alcher.dev/post/react-django-postgresql-dockerized-part-1-development-setup/"
---

## Introduction

[React](https://reactjs.org/) and [Django](https://djangoproject.com/) are both mature solutions to solve common development objectives. Bring in [PostgreSQL](https://postgresql.org/) into the mix as the primary data store, what we get is stack of battle-tested technologies that is a delight to work with.

## Goals

The goal of this series is to combine this stack with the power of [containerization using Docker](https://www.docker.com/resources/what-container). With Docker, we hope to achieve the following:

1. Easier onboarding and development setup, because the only dependency we need is Docker itself.
2. More streamlined continuous integration (CI) process, because tests can be ran within containers.
3. Better deployment process to cloud providers, because similarly, all we need is Docker itself to spin up our application services.
4. This leads to a better deployment pipeline for continuous delivery (CD), tying together our [DevOps Lifecycle](https://aws.amazon.com/devops/what-is-devops/).

This articles focuses on the first one.

## Starter Kit

Throughout this article, I'll be referencing the Starter Kit that I host on [Gitlab](https://gitlab.com/alchermd/react-django-postgresql-with-docker-starter-kit). This includes the `docker-compose.yml` file and the `Dockerfile` for each service defined. 

Please note that depending on when you are reading this article, the master branch may already have had a few changes. You can follow along with the [dev-setup branch](https://gitlab.com/alchermd/react-django-postgresql-with-docker-starter-kit/-/tree/dev-setup) for this article.

## Explanation

![Figure 1: Docker Development Setup Visualization](https://alcher.dev/img/RDP-dockerized-p1-setup-viz.png)

<center><em>Figure 1: Docker Development Setup Visualization</em></center>

The `web` service is responsible for the React frontend and the Django API. I find that combining the whole web tier into one service is the simplest approach, as opposed to deploying a separate service for the frontend. 

It utilizes a volume to map the contents of the `web` directory to the defined `WORKDIR` for that image. This is what allows changes from your machine to be reflected directly on the Docker container, allowing you to continue with the usual development cycle without rebuilding the containers for each change.

The following ports are then mapped to their respective counterparts on the host machine: `8000` for the Django API, `3000` is for the React dev server, and `35729` for the NodeJS livereload. 

[Environment Variables](https://docs.docker.com/compose/environment-variables/) are then loaded from the `.env.dev` file, allowing further customization if necessary.

Lastly, `stdin_open` is enabled to allow us to run the React dev server in interactive mode, giving us invaluable feedback as we write code.

Here's what the `docker-compose.yml` looks like for the `web` service:

```yaml
version: '3.7'

services:
  web:
    container_name: web
    build:
      context: ./web
      dockerfile: Dockerfile
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - ./web/:/usr/src/web/
    ports:
      - 8000:8000
      - 3000:3000
      - 35729:35729
    env_file:
      - ./.env.dev
    stdin_open: true
```

Next up is the `db` service. This is the PostgreSQL server that our Django API can communicate with for data persistence. We use the stock `12.0-alpine` image and define the credentials through environment variables. The container is then attached to a volume in order to persist the data throughout shutdowns and restarts.

We'll also make the `web` service depend on the `db` service. With conjunction to the `web/entrypoint.sh` file, this will ensure that Django won't try to connect to the PostgreSQL service while it's still booting up.

Here's what the final `docker-compose.yml` looks like after adding the `db` service:

```yaml
version: '3.7'

services:
  web:
    container_name: web
    build:
      context: ./web
      dockerfile: Dockerfile
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - ./web/:/usr/src/web/
    ports:
      - 8000:8000
      - 3000:3000
      - 35729:35729
    env_file:
      - ./.env.dev
    stdin_open: true
    depends_on:
      - db

  db:
    container_name: db
    image: postgres:12.0-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_USER=dev_user
      - POSTGRES_PASSWORD=dev_password
      - POSTGRES_DB=dev
    
volumes:
  postgres_data:
```

## Usage

We could run the services defined with just Docker installed in our machine, but that won't be suitable for a productive development setup. 

I suggest to have `npm` installed in order to build the `node_modules` on our host machine, which is then accessible through the volume in the `web` service. This enables IDE autocompletion for the React part.

Python, on the other hand, is much more forgiving with this regard. There are a couple of high quality extensions for your favorite IDE that allows you to connect to a remote server (in this case to our Docker container). Here's some helpful articles to get you started:

- [PyCharm](https://www.jetbrains.com/help/pycharm/using-docker-as-a-remote-interpreter.html#example)
- [VSCode](https://code.visualstudio.com/docs/remote/containers)
- [IntelliJ](https://www.jetbrains.com/help/idea/configuring-remote-python-sdks.html)

To get started we need to run the following commands:

```bash
$ cp .env .env.dev                                       # <- 0
$ chmod +x web/entrypoint.sh                             # <- 1
$ npm install --prefix ./web/frontend/                   # <- 2
$ docker-compose up -d --build                           # <- 3
$ docker-compose exec web npm start --prefix ./frontend/ # <- 4
```

0. The contents of `.env` should be good enough as is, but you can reconfigure it as needed.
1. Make the entrypoint executable.
2. React dependencies are then installed on our host machine for IDE autocompletion.
3. The images are then built, and the containers ran in [detached mode](https://docs.docker.com/engine/reference/run/#detached--d). The files generated in the previous step is also copied over to the `web` container.
4. We can now boot up the React dev server, with hot reload enabled.

You can now access the React application on [http://localhost:3000/](http://localhost:3000/) and the Django API on [http://localhost:8000/](http://localhost:8000/). Click on the button to test if your frontend is integrated with the API:

![Figure 2: React integrated with Django on Docker containers](https://alcher.dev/img/RDP-dockerized-p1-integration.png)

<center><em>Figure 2: React integrated with Django on Docker containers</em></center>

If you get the *"API Integration Works!"* alert, you're good to go!

## Conclusion

In this article, we took a glance on a development setup for a React+Django+PostgreSQL stack using Docker containers. We reviewed the overview of the architecture for this setup, the details of each services, and how they connect to the host (and among themselves).

For the next article, we'll implement a Continuous Integration (CI) pipeline for our stack.

I'll see you then.