From 23840aa86d165cc8025096ad9606d947df8f32f8 Mon Sep 17 00:00:00 2001 From: John Taylor <62556052+john-fueled@users.noreply.github.com> Date: Wed, 20 Dec 2023 08:51:05 -0500 Subject: [PATCH] feat(fly-io): Added fly.io template files (#475) Added fly.io template files for a deployable Dockerfile and Github actions. > Why was this change necessary? Spin up a hosted development environment fast. > How does it address the problem? Adds fly.io as an optional deployment destination. > Are there any side effects? The local and dev Dockerfiles do not have the same configuration that Fly.io expects. When deploying the `dev` Dockerfile, Fly.io deploys hang due to the `entrypoint` script running the gunicorn command which never exits. Therefore a separate `compose/fly` folder has the necessary changes to pass the build process. Addresses #466 --------- Co-authored-by: Suneet Choudhary --- .gitignore | 4 ++ README.md | 1 + cookiecutter.json | 1 + hooks/post_gen_project.sh | 5 ++ .../.github/workflows/fly.yml | 15 +++++ {{cookiecutter.github_repository}}/README.md | 36 +++++++++-- .../compose/fly/django/Dockerfile | 64 +++++++++++++++++++ 7 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 {{cookiecutter.github_repository}}/.github/workflows/fly.yml create mode 100644 {{cookiecutter.github_repository}}/compose/fly/django/Dockerfile diff --git a/.gitignore b/.gitignore index 132f213e..fd82c3f6 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,7 @@ Session.vim # Pycharm project modules .idea/ + + +### VSCode +.vscode/ \ No newline at end of file diff --git a/README.md b/README.md index 7bf445dd..1ae69a7c 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ ### Optional - Heroku Setup +- Fly Setup - Ubuntu 20 LTS via [Ansible] - Celery with flower integration. - AWS S3 media storage diff --git a/cookiecutter.json b/cookiecutter.json index f983e873..8d1f77cf 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -10,6 +10,7 @@ , "add_newrelic" : "y" , "add_postgis": "n" , "add_heroku": "n" + , "add_fly": "n" , "enable_whitenoise": "n" , "add_ansible": "y" , "letsencrypt": "y" diff --git a/hooks/post_gen_project.sh b/hooks/post_gen_project.sh index 27f13ed4..bbaf9820 100755 --- a/hooks/post_gen_project.sh +++ b/hooks/post_gen_project.sh @@ -29,6 +29,11 @@ if echo "{{ cookiecutter.add_heroku }}" | grep -iq "^n"; then rm -rf uwsgi.ini Procfile runtime.txt bin/post_compile fi +if echo "{{ cookiecutter.add_fly }}" | grep -iq "^n"; then + rm .github/workflows/fly.yml + rm -rf compose/fly +fi + if echo "{{ cookiecutter.add_ansible }}" | grep -iq "^n"; then rm -rf provisioner Vagrantfile ansible.cfg fi diff --git a/{{cookiecutter.github_repository}}/.github/workflows/fly.yml b/{{cookiecutter.github_repository}}/.github/workflows/fly.yml new file mode 100644 index 00000000..13e98718 --- /dev/null +++ b/{{cookiecutter.github_repository}}/.github/workflows/fly.yml @@ -0,0 +1,15 @@ +name: Fly Deploy +on: + push: + branches: + - master +jobs: + deploy: + name: Deploy app + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: superfly/flyctl-actions/setup-flyctl@master + - run: flyctl deploy --dockerfile ./compose/fly/django/Dockerfile + env: + FLY_API_TOKEN: ${{ "{{" }} secrets.FLY_API_TOKEN {{ "}}" }} diff --git a/{{cookiecutter.github_repository}}/README.md b/{{cookiecutter.github_repository}}/README.md index 592b7e8c..1e8ce89a 100644 --- a/{{cookiecutter.github_repository}}/README.md +++ b/{{cookiecutter.github_repository}}/README.md @@ -1,7 +1,6 @@ -{{ cookiecutter.project_name }} -============================== +# {{ cookiecutter.project_name }} -__Version:__ {{ cookiecutter.version }} +**Version:** {{ cookiecutter.version }} {{ cookiecutter.project_description }} @@ -9,7 +8,7 @@ __Version:__ {{ cookiecutter.version }} {% if cookiecutter.add_docker == 'y' %} !!! note - For setting up locally using `Docker`, check [here](docs/backend/docker_setup.md) +For setting up locally using `Docker`, check [here](docs/backend/docker_setup.md) {% endif %} Minimum requirements: **pip, python3.9, poetry, redis & [PostgreSQL 11][install-postgres]{% if cookiecutter.add_postgis.lower() == "y" %} with postgis-2.4{% endif %}**, setup is tested on Mac OSX only. @@ -43,7 +42,7 @@ Running `poetry lock` generates `poetry.lock` which has all versions pinned. You can install Poetry by using `pip install --pre poetry` or by following the official installation guide [here](https://github.com/python-poetry/poetry#installation). -*Tip:* We recommend that you use this workflow and keep `pyproject.toml` as well as `poetry.lock` under version control to make sure all computers and environments run exactly the same code. +_Tip:_ We recommend that you use this workflow and keep `pyproject.toml` as well as `poetry.lock` under version control to make sure all computers and environments run exactly the same code. ### Other tools @@ -61,13 +60,38 @@ poetry export --without-hashes -f requirements.txt -o requirements_dev.txt --wit , respectively. - ## Deploying Project The deployment are managed via travis, but for the first time you'll need to set the configuration values on each of the server. Check out detailed server setup instruction [here](docs/backend/server_config.md). +{% if cookiecutter.add_fly == 'y' %} + +### Develop on Fly.io + +Create a [fly.io](https://fly.io) account. + +Install `flyctl` and run the following commands to set up the Fly.io application, it will ask a series of questions regarding deployment configuration. + +``` +brew install flyctl +fly lauch +``` + +When ready to deploy, simply run the command using the Fly Dockerfile: + +``` +flyctl deploy --dockerfile ./compose/fly/django/Dockerfile +``` + +There is also a Github Action provided `.github/workflows/fly.yml` to deploy the application on the `master` branch. In order to deploy from CI: + +1. Create Fly Access Token [here](https://fly.io/user/personal_access_tokens). +2. Add the `FLY_API_TOKEN` to the Github repo secrets [here](https://github.com/{{cookiecutter.github_username}}/{{cookiecutter.github_repository}}/settings/secrets/actions) + +{% endif %} + ## How to release {{ cookiecutter.project_name }} Execute the following commands: diff --git a/{{cookiecutter.github_repository}}/compose/fly/django/Dockerfile b/{{cookiecutter.github_repository}}/compose/fly/django/Dockerfile new file mode 100644 index 00000000..73dffc89 --- /dev/null +++ b/{{cookiecutter.github_repository}}/compose/fly/django/Dockerfile @@ -0,0 +1,64 @@ +ARG PYTHON_VERSION=3.9-slim-buster + +# define an alias for the specfic python version used in this file. +FROM python:${PYTHON_VERSION} as python + +ENV POETRY_VERSION=1.3.2 + +ARG BUILD_ENVIRONMENT=dev +ARG APP_HOME=/app + +ENV PYTHONUNBUFFERED 1 +ENV PYTHONDONTWRITEBYTECODE 1 +ENV BUILD_ENV ${BUILD_ENVIRONMENT} + +WORKDIR ${APP_HOME} + +RUN addgroup --system django \ + && adduser --system --ingroup django django + +# Install required system dependencies +RUN apt-get update && apt-get install --no-install-recommends -y \ + # dependencies for building Python packages + build-essential \ + # psycopg2 dependencies + libpq-dev \ + # Translations dependencies + gettext \ + # Versatile image field & pillow \ + libmagic1 \ + libmagic-dev \ + + # cleaning up unused files + && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ + && rm -rf /var/lib/apt/lists/* + +# Install Poetry +RUN pip install --no-cache-dir poetry==${POETRY_VERSION} + +COPY poetry.lock pyproject.toml ${APP_HOME}/ + +# Project initialization: +RUN poetry config virtualenvs.create false && poetry install --no-interaction --no-ansi + +COPY --chown=django:django ./compose/dev/django/celery/worker/start /start-celeryworker +RUN chmod +x /start-celeryworker + + +COPY --chown=django:django ./compose/dev/django/celery/beat/start /start-celerybeat +RUN chmod +x /start-celerybeat + + +COPY ./compose/dev/django/celery/flower/start /start-flower +RUN chmod +x /start-flower + +COPY --chown=django:django . ${APP_HOME} + +# make django owner of the WORKDIR directory as well. +RUN chown django:django ${APP_HOME} + +RUN python manage.py collectstatic --noinput + +EXPOSE 8000 + +CMD ["gunicorn", "--bind", ":8000", "--workers", "2", "wsgi:application"]