Skip to content

Commit 895544b

Browse files
authored
Merge pull request #21 from cmu-delphi/set-up-deployment
Prepares this application for deployment
2 parents 671682b + 095e0f3 commit 895544b

File tree

8 files changed

+160
-17
lines changed

8 files changed

+160
-17
lines changed

.ci.env

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# This file is used to allow CI to start the compose services. It will typcially
2+
# not need to be modified.
3+
4+
MYSQL_DATABASE=mysql_database
5+
MYSQL_USER=mysql_user
6+
MYSQL_PASSWORD=mysql_password
7+
MYSQL_PORT=3306
8+
MYSQL_ROOT_PASSWORD=test123!
9+
MYSQL_HOST=db
10+
11+
ALLOWED_HOSTS='127.0.0.1,localhost'
12+
CORS_ORIGIN_WHITELIST='http://127.0.0.1:3000,http://localhost:3000'
13+
CSRF_TRUSTED_ORIGINS='http://127.0.0.1:8000,http://localhost:8000'
14+
15+
SECRET_KEY='secret_key'
16+
DEBUG='True'
17+
18+
# Add the following to your local .env file. They will be used in the CI process
19+
# and you can largely forget about them, but including them in your .env file
20+
# will act like a safe default and help suppress warnings.
21+
REGISTRY=""
22+
TAG=""

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,9 @@ CSRF_TRUSTED_ORIGINS='http://127.0.0.1:8000,http://localhost:8000'
1111

1212
SECRET_KEY='secret_key'
1313
DEBUG='True'
14+
15+
# Add the following to your local .env file. They will be used in the CI process
16+
# and you can largely forget about them, but including them in your .env file
17+
# will act like a safe default and help suppress warnings.
18+
REGISTRY=""
19+
TAG=""
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: 'Build and deploy application containers'
2+
on:
3+
push:
4+
jobs:
5+
build-tag-push-deploy:
6+
runs-on: ubuntu-latest
7+
# CI/CD will run on these branches
8+
if: >
9+
github.ref == 'refs/heads/master' ||
10+
github.ref == 'refs/heads/development'
11+
strategy:
12+
matrix:
13+
# Specify the docker-compose services to build images from
14+
service: [sdwebapp, sdnginx]
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v3
18+
- name: Login to GitHub container registry
19+
uses: docker/login-action@v1
20+
with:
21+
registry: ghcr.io
22+
username: cmu-delphi-deploy-machine
23+
password: ${{ secrets.CMU_DELPHI_DEPLOY_MACHINE_PAT }}
24+
- name: Create container image tags
25+
id: image-tag
26+
run: |
27+
baseRef="${GITHUB_REF#*/}"
28+
baseRef="${baseRef#*/}"
29+
case "${baseRef}" in
30+
master)
31+
image_tag="latest"
32+
;;
33+
*)
34+
image_tag="${baseRef//\//_}" # replace `/` with `_` in branch name
35+
;;
36+
esac
37+
echo "IMAGE_TAG=${image_tag}" >> $GITHUB_OUTPUT
38+
- name: Copy env file
39+
run: |
40+
cp ./.ci.env ./.env
41+
- name: Set up docker-compose
42+
uses: ndeloof/[email protected]
43+
- name: docker-compose build --push
44+
run: |
45+
docker-compose build --push ${{ matrix.service }}
46+
env:
47+
TAG: ":${{ steps.image-tag.outputs.IMAGE_TAG }}"
48+
REGISTRY: "ghcr.io/${{ github.repository_owner }}/"
49+
- name: docker-compose down
50+
run: |
51+
docker-compose down
52+
- name: Trigger smee.io webhook to pull new container images
53+
run: |
54+
curl -H "Authorization: Bearer ${{ secrets.DELPHI_DEPLOY_WEBHOOK_TOKEN }}" \
55+
-X POST ${{ secrets.DELPHI_DEPLOY_WEBHOOK_URL }} \
56+
-H "Content-Type: application/x-www-form-urlencoded" \
57+
-d "repository=ghcr.io/${{ github.repository }}-${{ matrix.service }}&tag=${{ steps.image-tag.outputs.IMAGE_TAG }}"

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ RUN apt-get install python3 -y
1212
RUN apt-get install python3-pip -y
1313
RUN python3 -m pip install --upgrade pip
1414
RUN pip3 install pipenv
15+
RUN pipenv lock
1516
RUN pipenv requirements > requirements.txt
1617
RUN pip3 install -r requirements.txt
1718

1819
WORKDIR /home/python
19-
# RUN pipenv install --system --deploy
2020
COPY /src .
2121
COPY /gunicorn/gunicorn.py .
2222
ENV PATH="/home/python/.local/bin:${PATH}"

Pipfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ django-coverage-plugin = "*"
2727
django-extensions-models = "*"
2828
mypy = "*"
2929
django-stubs = "*"
30+
tzdata = "*"
3031

3132
[dev-packages]
3233
flake8 = "*"

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,27 @@ $ docker-compose up
7777

7878
Open `http://localhost:8000` to view it in the browser
7979

80+
### To run via docker and emulate production
81+
82+
Though probably not necessary in most cases, if you want to test/modify/emulate how this will run in production you can:
83+
84+
- In `.env` set:
85+
```
86+
DEBUG = 'False'
87+
```
88+
- Modify the app container's command in `docker-compose.yaml` to run:
89+
```
90+
gunicorn signal_documentation.wsgi:application --bind 0.0.0.0:8000"
91+
92+
*(Essentially you'll replace just the last line of the command, switching out the "runserver" line)
93+
```
94+
95+
Open `http://localhost` to view it in the browser. In this usage your request will be serviced by Nginx instead of the application directly.
96+
97+
The primary use case for this will be when making changes to the Nginx container image that runs in production and hosts the static file content, or also if making changes to the Gunicorn config.
98+
99+
Changes of this sort should be carefully evaluated as they may require interaction with systems managed by devops folks.
100+
80101
## [Django admin](https://docs.djangoproject.com/en/4.1/ref/contrib/admin/) web interface (user should be `is_staff` or `is_superuser`)
81102
`http://localhost:8000/admin`
82103

@@ -126,3 +147,22 @@ Othervice you will receive Errors during import process:
126147
3. Import `Signal.base` fields with `SignalBaseResource` - [http://localhost:8000/admin/signals/signal/import/](http://localhost:8000/admin/signals/signal/import/)
127148
![Import `Signal.base` field](./docs/image-5.png)
128149
![Confirm importing `Signal.base` fields](./docs/image-6.png)
150+
151+
## Deployment
152+
153+
This application gets deployed (at a minimum) to two environmetns:
154+
155+
Production - <https://delphi.cmu.edu/{app_name}>
156+
157+
Staging - <https://staging.delphi.cmu.edu/{app_name}>
158+
159+
Each environment is essentially a bunch of different services all governed by `docker-compose`, running across multiple hosts, with various layering of proxies and load balancers.
160+
161+
### Basic workflow
162+
163+
- A PR merged to either `development` or `master` will trigger CI to build container images that are then tagged (based on the branch name and ":latest" respectively) and stored in our GitHub Packages container image repository.
164+
- CI triggers a webhook that tells the host systems to pull and run new container images and restart any services that have been updated.
165+
166+
### Control of the deployed environment
167+
168+
The environment and secrets used for deployment live in <https://github.com/cmu-delphi/delphi-ansible-web>. Any changes to the environment should be made there and then tested and validated by devops folks.

docker-compose.yaml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ services:
77
container_name: signal_documentation-db
88
restart: always
99
env_file:
10-
- ./.env
10+
- ./.env
1111
environment:
1212
MYSQL_DATABASE: ${MYSQL_DATABASE}
1313
MYSQL_USER: ${MYSQL_USER}
@@ -18,11 +18,13 @@ services:
1818
ports:
1919
- "3306:3306"
2020

21-
webapp:
21+
sdwebapp:
22+
image: ${REGISTRY}signal_documentation-webapp${TAG}
2223
build: .
2324
env_file:
24-
- ./.env
25-
container_name: signal_documentation-web
25+
- ./.env
26+
container_name: signal_documentation-webapp
27+
restart: on-failure
2628
command: sh -c "python3 /usr/src/signal_documentation/src/manage.py migrate --noinput &&
2729
python3 /usr/src/signal_documentation/src/manage.py collectstatic --noinput &&
2830
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/available_geography.json &&
@@ -44,6 +46,20 @@ services:
4446
ports:
4547
- "6379:6379"
4648

49+
sdnginx:
50+
image: ${REGISTRY}signal_documentation-nginx${TAG}
51+
build: ./nginx
52+
env_file:
53+
- ./.env
54+
container_name: signal_documentation-nginx
55+
restart: on-failure
56+
volumes:
57+
- ./src/staticfiles:/staticfiles
58+
ports:
59+
- "80:80"
60+
depends_on:
61+
- sdwebapp
4762
volumes:
4863
mysql:
4964
webapp:
65+
static:

nginx/default.conf.template

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
server {
2-
listen 80;
3-
server_name _;
2+
listen 80;
3+
server_name sdnginx;
44

5-
location / {
6-
proxy_set_header Host $http_host;
7-
proxy_set_header X-Real-IP $remote_addr;
8-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
9-
proxy_set_header X-Forwarded-Proto $scheme;
10-
proxy_pass http://${APP_HOST}:8000;
11-
}
5+
location /static/ {
6+
autoindex on;
7+
alias /staticfiles/;
8+
}
129

13-
location /usr/src/signal_documentation {
14-
alias /static/;
15-
}
10+
location / {
11+
proxy_pass http://sdwebapp:8000/;
12+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
13+
proxy_set_header Host $http_host;
14+
proxy_set_header X-Real-IP $remote_addr;
15+
proxy_set_header X-Forwarded-Proto $scheme;
16+
}
1617
}

0 commit comments

Comments
 (0)