Skip to content

Deployment

ochan1 edited this page Feb 14, 2023 · 2 revisions

Quickstart

All of the following commands should be done in the Conda Virtual Environment (after conda activate tbpweb-dev).

This requires fabric, a Python SSH task runner, to be installed and accessible. As it is listed as a dependency in the config/requirements.txt, it is installed via Pip during while the Conda environment is set up.

Then, deploy a release with the following command in your Python:

fab deploy

If your SSH key to the apphost requires a password to unlock, the --prompt-for-passphrase flag will allow you to input it:

fab --prompt-for-passphrase deploy

If you have no SSH key to the apphost (shame on you), and require password authentication, the --prompt-for-login-password will allow you input it:

fab --prompt-for-login-password deploy

The prod deploy config (in the fabfile) will fetch the TBP-IT/tbpweb repo's master branch over HTTPS, then extract it to a timestamped release folder under ~/tbpweb/prod/releases.

Then the timestamped folder will be linked to ~/tbpweb/prod/current and then restart the server (via systemctl (see "Reloading"))

This means that, by default, your commits must be pushed to the "TBP-IT" repo under the "master" branch before deploying. It does not copy the code from your computer.

Note: this does not require SSH access to the Github repo, only SSH access to the apphost.

During the development of features to the Django website, the "fab" script is written where the tbpweb website will always deploy to https://tbp.berkeley.edu

Custom deploys

If you are, for some reason, deploying from a different branch, then you should edit the fabfile.py targets dict to specify a new deploy target, by overriding the defaults just above it:

targets = {
    'prod': {
        'deploy': {
            'name': 'prod',
            'branch': 'master',
        },
    },
    'custom-target': {
        'deploy': {
            'name': 'custom',
            'branch': 'my-branch',
            'repo_url': 'my-fork-url',
        },
    },
 }

Then select the custom target by using the custom made --target flag (not part of fab) [By default, the prod target is used]##

fab deploy --target custom-target

Rollback to Past Version

Use:

fab rollback --release <Timestamp of Folder>`

replacing the <Timestamp of Folder> with only the Folder Name you want to rollback to in ~/tbpweb/prod/releases/ (you don't need the full path, just the name of the specific folder inside the "releases" folder)

Manual Instructions

  1. SSH into the OCF Server at [email protected]

  2. Get the full path of the folder that you want to link (currently, all past versions of the website is located inside ~/tbpweb/prod/releases/). You may use realpath <file or folder name> to get the full path, where <file or folder name> is the name of the file starting from the current directory you are at on your terminal (replacing between and including the "<" and ">").

  3. Get the path of the "current" folder (currently, all past versions of the website is located inside ~/hknweb/prod/current/). You may also use realpath <file or folder name> to get the full path, where <file or folder name> is the name of the file starting from the current directory you are at on your terminal (replacing between and including the "<" and ">").

  4. Run this command: ln -sfn <Full Path of Release Timestamp Folder> <Full Path of the Current Symlink>, replacing <Full Path of Release Timestamp Folder> with the path you got in Step 1 and <Full Path of the Current Symlink> with the path you got in Step 2 (with both replacing between and including the "<" and ">"). For example, ln -sfn /home/h/hk/hkn/hknweb/prod/releases/20210103_212211 /home/h/hk/hkn/hknweb/prod/current

  5. Run systemctl --user restart hknweb.service to restart the Server

Details

Deployment will be run using fabric, a Python SSH task runner.

Since the Django runserver builtin server isn't actually a very good web server (it's designed for one user, not hundreds), we use a different web server called gunicorn on the OCF.

Our deployment will be to the OCF's apphost server, https://apphost.ocf.berkeley.edu/. The OCF's documentation for running apps can be found here.

Our public-facing domains are:

Dependencies

Nothing! You should have already installed everything in setup.

Instructions


[NOTE: This command does not work as of January 3, 2021. This is an old command. Will post once an equivalent is found. For now, the above "fab deploy" and similar commands should suffice, and if another SSH destination is needed, edit the "user" and "host" part in hkn_defaults inside fabfile.py]

From the .venv Virtual Environment, run the command:

fab -R <environment> -H [email protected] deploy

We will have two environments:

  • prod: production, publicly visible, contains important user data
  • test: testing, publicly visible, but may be wiped

We will push proposed changes to test, and finally to prod once the changes are confirmed working.


During Development, the "fab" script is written where the hknweb website will always deploy to https://dev-hkn.eecs.berkeley.edu

Tasks

So what do we need to get deployment working?

Downloading

We download a copy of the code, from the Github master branch. This will allow us to control which version of code to deploy, and restrict push access to core developers.

We should download a copy, and not simply git pull. This is because we want to allow rollbacks, and we don't want rogue files laying around forever, and we want a controlled environment as much as possible.

Setup

The fake README describes the deploy process in detail, which follows the Capistrano model from Ruby:

  1. Inside a deploy_path, create a releases, shared, and repo directory.
  2. Clone a repository into the repo directory.
  3. Extract a configurable branch into a subdirectory of the releases directory.
  4. Symlink that subdirectory to a current folder in the deploy_path
  5. Symlink shared files/folders in shared into current.

What this means is that the folder structure in the deploy server (apphost.ocf.berkeley.edu) should look like this:

~/hknweb/
    prod/
        current/ -> <release symlink>
        releases/
        shared/
        repo/
    test/
        current/ -> <release symlink>
        releases/
        shared/
        repo/

<release symlink> means that a website code timestamped folder is symlinked (similar to your conventional "shortcuts" or "alias") located inside releases/

Reloading

Our website runs using gunicorn, and is managed by systemd (see the Ubuntu and Arch Linux docs). When we deploy a new version of the website, we have to restart it using systemd:

systemctl --user restart hknweb.service

This also means that when the OCF takes down their servers for maintenance, when they are turned on our website is also turned on automatically.

This depends on two files, a run script in our repo and a systemd unit script on the apphost: ~/.config/systemd/user/hknweb.service.

  • hknweb.service describes how to run and restart our server
  • run describes the actual gunicorn command to run an instance of our server

Supervisor (Gunicorn)

Gunicorn has a green-thread worker model. This means that it controls multiple worker processes to handle requests, from a single master process which distributes requests.

Green threads, or m-to-n threads, means that every process has its own thread scheduler, instead of using the OS (kernel) thread scheduler. The idea is that since we know what kind of task we need to do, I/O heavy web requests (which the OS can't assume), we can figure out how much CPU% to give to each task ourselves, and do so more efficiently.

More technically, it means that we map any m task threads to some n OS threads.