Skip to content

Commit

Permalink
Update to 0.7.3 release
Browse files Browse the repository at this point in the history
  • Loading branch information
turukawa committed Feb 28, 2023
1 parent 0c920d6 commit 6c77945
Show file tree
Hide file tree
Showing 2 changed files with 316 additions and 0 deletions.
311 changes: 311 additions & 0 deletions DEPLOYMENT-README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
# Step-by-step production deployment guide

There are easier ways to run a blog. You will find the resource requirements for this stack quite substantive. This really is if you intend to run some complex web service and need all the architecture.

> **NOTE**: this is a more focused, step-by-step version of the generated "README". You will find a few more details there, especially about customising larger deployments, or changing your configuration after deployment. This is designed to get you up-and-running with your first production deployment in a controlled way. No guarantees, though.
## Preparation

### Committing to GitHub

Prepare your code and resources for your first commit. There are three files which must **not** be committed unless you're quite positive your data will never leak.

- `/.env`
- `/cookiecutter-config-file.yml`
- `/frontend/.env`

These files will also need to be customised for production deployment. Make alternative arrangements for these files. Don't trust `.gitignore` to save you.

### DigitalOcean Droplets

This guide uses [DigitalOcean Droplets](https://www.digitalocean.com/pricing/droplets), so customise as required. Deploy to the smallest (currently 500MiB memory, 1 vCPU and 10GiB SSD for $4/month). You can upgrade later when you know your resource requirements.

> **WARNING**: if you're using `neo4j` then the `java` server alone will need 1Gb of memory, and you may need a 2Gb to 4Gb base droplet. Plan accordingly. If you decide not to use it, you will need to carefully remove it. That will require editing `docker-compose.yml` and the start-up sequence in the backend. Shouldn't be too challenging.
Ensure you add your SSH encryption keys on launch so that your server can be secure from the beginning.

Deploy on whatever server image your prefer, although the default would be Ubuntu 20.04 (22.04 is the latest). End-of-life for 20.04 is April 2030, and for 22.04 is April 2032. You have time. The underlying image isn't that critical, as you'll be using the Docker images at their current versions.

### Domain name and email

Get your settings and redirects at your registrar, and then set up the various DNS records at DigitalOcean, pointing at the IP address for the droplet you set up.

For reference:
- [Link Namecheap domain to DigitalOcean](https://www.namecheap.com/support/knowledgebase/article.aspx/10375/2208/how-do-i-link-a-domain-to-my-digitalocean-account/)
- [Manage DNS records at DigitalOcean](https://docs.digitalocean.com/products/networking/dns/how-to/manage-records/)

Don't forget to create DNS A records for `flower`, `neo4j`, `traefik`, and `pgadmin`.

Now you should be able to login to your server and begin deployment.

## Deployment

### Docker

Update your server, and install all required packages:

```shell
# Install the latest updates
apt-get update
apt-get upgrade -y
```

Then:

```shell
# Download Docker
curl -fsSL get.docker.com -o get-docker.sh
# Install Docker using the stable channel (instead of the default "edge")
CHANNEL=stable sh get-docker.sh
# Remove Docker install script
rm get-docker.sh
```

### Clone your repository

The basic approach is to clone from GitHub then set up the appropriate `.env` files and any custom `conf` files called from `docker-compose`. If yours is a private repo, review the GitHub docs for how to set that up.

Remember you can create new passwords as follows:

```bash
openssl rand -hex 32
# Outputs something like: 99d3b1f01aa639e4a76f4fc281fc834747a543720ba4c8a8648ba755aef9be7f
```

From `/srv`:

```shell
git clone https://github.com/<user-name>/<project-name>.git
```

Then continue from the project directory `/srv/<project-name>`. You can always pull your latest code from that directory, with:

```shell
git pull
```

### Docker Swarm Mode

Deploy the stack to a Docker Swarm mode cluster with a main Traefik proxy, set up using the ideas from [DockerSwarm.rocks](https://dockerswarm.rocks). And you can use CI (continuous integration) systems to do it automatically.

This stack expects the public Traefik network to be named `traefik-public`.

```bash
export USE_HOSTNAME=example.com
```

```bash
# Set up the server hostname
echo $USE_HOSTNAME > /etc/hostname
hostname -F /etc/hostname
```

Set up **Swarm Mode**:

```shell
docker swarm init
```

If this fails, you'll need to explicitly link the public IP for the droplet:

```shell
docker swarm init --advertise-addr 123.123.123.123
```

You can add additional manager and worker nodes. This is optional and you can read the DockerSwarm.rocks link for more.

Check that the nodes are connected and running:

```shell
docker node ls
```

Which would output something like:

```
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
ndcg2iavasdfrm6q2qwere2rr * dog.example.com Ready Active Leader 18.06.1-ce
```

### Traefik Proxy with HTTPS

Follow the documentation from DockerSwarm.rocks to [get automatic HTTPS certificates](https://dockerswarm.rocks/traefik/).

Create a network that will be shared with Traefik and the containers that should be accessible from the outside, with

```shell
docker network create --driver=overlay traefik-public
```

Get the Swarm node ID of this node and store it in an environment variable (use the code below exactly):

```shell
export NODE_ID=$(docker info -f '{{.Swarm.NodeID}}')
```

Create a tag in this node, so that Traefik is always deployed to the same node and uses the same volume:

```shell
docker node update --label-add traefik-public.traefik-public-certificates=true $NODE_ID
```

Create an environment variable with your email, to be used for the generation of Let's Encrypt certificates, e.g.:

```shell
export [email protected]
```

Create an environment variable with the domain you want to use for the Traefik UI (user interface), e.g.:

```shell
export DOMAIN=traefik.example.com
```

You will access the Traefik dashboard at this domain, e.g. `traefik.example.com`.

Create an environment variable with a username (you will use it for the HTTP Basic Auth for Traefik and Consul UIs), for example:

```shell
export USERNAME=admin
```

Create an environment variable with the password, e.g.:

```shell
export PASSWORD=changethis
```

Use `openssl` to generate the "hashed" version of the password and store it in an environment variable:

```shell
export HASHED_PASSWORD=$(openssl passwd -apr1 $PASSWORD)
```

Download the file `traefik.yml`:

```shell
curl -L dockerswarm.rocks/traefik.yml -o traefik.yml
```

Deploy the stack with:

```shell
docker stack deploy -c traefik.yml traefik
```

It will use the environment variables you created above. Check if the stack was deployed with:

```bash
docker stack ps traefik
```

It will output something like:

```
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
w5o6fmmln8ni traefik_traefik.1 traefik:v2.2 dog.example.com Running Running 1 minute ago
```

You can check the Traefik logs with:

```bash
docker service logs traefik_traefik
```

### Deploy to a Docker Swarm mode cluster

There are 4 (5) steps:

1. **Pull** your git repo
2. **Build** your app images
3. **Deploy** your stack
4. **Restart** your docker service

---

Here are the steps in detail:

1. **Pull** your git repo

```bash
cd /srv/example
```
```bash
sudo git pull
```

2. **Build your app images**

* Set these environment variables, right before the next command:
* `TAG=prod`
* `FRONTEND_ENV=production`
* Use the provided `scripts/build.sh` file with those environment variables:

```bash
TAG=prod DOMAIN=example.com STACK_NAME=example-com TRAEFIK_TAG=example.com FRONTEND_ENV=production bash -x scripts/build.sh
```

**Persisting Docker named volumes**

You can use [`docker-auto-labels`](https://github.com/tiangolo/docker-auto-labels) to automatically read the placement constraint labels in your Docker stack (Docker Compose file) and assign them to a random Docker node in your Swarm mode cluster if those labels don't exist yet.

To do that, you can install `docker-auto-labels`:

```bash
pip install docker-auto-labels
```

And then run it passing your `docker-stack.yml` file as a parameter:

```bash
docker-auto-labels docker-stack.yml
```

You can run that command every time you deploy, right before deploying, as it doesn't modify anything if the required labels already exist.

3. **Deploy your stack**

* Set these environment variables:
* `DOMAIN=example.com`
* `TRAEFIK_TAG=example.com`
* `STACK_NAME=example-com`
* `TAG=prod`
* Use the provided `scripts/deploy.sh` file with those environment variables:

```bash
DOMAIN=example.com TRAEFIK_TAG=example.com STACK_NAME=example-com TAG=prod bash -x scripts/deploy.sh
```

4. **Restart** your docker service

```bash
sudo service docker restart
```

You may need to prune regularly while developing if you find yourself running out of space:

```shell
docker system prune
```

## URLs

These are the URLs that will be used and generated by the project.

### Production URLs

Production URLs, from the branch `production`.

Frontend: https://example.com

Backend: https://example.com/api/

Automatic Interactive Docs (Swagger UI): https://example.com/docs

Automatic Alternative Docs (ReDoc): https://example.com/redoc

PGAdmin: https://pgadmin.example.com

Flower: https://flower.example.com

Traefik: https://traefik.example.com
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ After using this generator, your new project (the directory created) will contai

See notes and [releases](https://github.com/whythawk/full-stack-fastapi-postgresql/releases).

### 0.7.3
- @nuxt/content 2.2.1 -> 2.4.3
- Fixed: `@nuxt/content` default api, `/api/_content`, conflicts with the `backend` api url preventing content pages loading.
- Documentation: Complete deployment guide in `DEPLOYMENT-README.md`

### 0.7.2
- Fixed: URLs for recreating project in generated `README.md`. PR [#15](https://github.com/whythawk/full-stack-fastapi-postgresql/pull/15) by @FranzForstmayr
- Fixed: Absolute path for mount point in `docker-compose.override.yml`. PR [#16](https://github.com/whythawk/full-stack-fastapi-postgresql/pull/16) by @FranzForstmayr
Expand Down

0 comments on commit 6c77945

Please sign in to comment.