Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign Build Deployment Process (External) #125

Merged
merged 73 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
6aed57a
Create image_build_push.yml
MukuFlash03 Mar 18, 2024
8b0317f
Added docker build and push for dashboard and notebook images + Updat…
Mar 22, 2024
7d3cd86
Merge pull request #2 from MukuFlash03/image-push
MukuFlash03 Mar 22, 2024
355db20
Changed sed to jq + Renamed docker image in image_push
Mar 26, 2024
3c17d18
Merge pull request #3 from MukuFlash03/image-push
MukuFlash03 Mar 26, 2024
e402a61
Added TODO to change image push branch
Mar 26, 2024
ffcdbc8
Merge pull request #4 from MukuFlash03/image-push
MukuFlash03 Mar 26, 2024
d6a6809
Removed printing Docker username
Mar 26, 2024
102899a
Merge pull request #5 from MukuFlash03/image-push
MukuFlash03 Mar 26, 2024
50a7b63
Added cert.sh + Modified Dockerfiles
Mar 28, 2024
db85f75
Merge pull request #6 from MukuFlash03/image-push
MukuFlash03 Mar 28, 2024
2dab7a1
Removing ENV variables from Dockerfile
Apr 3, 2024
43f3d5a
Merge pull request #7 from MukuFlash03/image-push
MukuFlash03 Apr 3, 2024
89ed59a
Removed sed / jq usage from start scripts
Apr 12, 2024
37c7599
Merge pull request #8 from MukuFlash03/image-push
MukuFlash03 Apr 12, 2024
e962d13
Changing base image to build from redesign server image
Apr 12, 2024
8d2464d
Bumped up base server image tag
Apr 16, 2024
d49a275
Merge branch 'image-push-merge' into image-push
MukuFlash03 Apr 16, 2024
efaf216
Merge pull request #9 from MukuFlash03/image-push
MukuFlash03 Apr 16, 2024
baac678
Bump up base server image tag
Apr 16, 2024
629b3a1
Merge pull request #10 from MukuFlash03/image-push
MukuFlash03 Apr 16, 2024
fee9437
Artifact download test - 1
Apr 26, 2024
9622279
Bumped up server image tag
Apr 30, 2024
6e3f2be
Artifact + Matrix - 1
May 2, 2024
1745634
Artifact + Matrix - 2
May 2, 2024
21ca992
Artifact + Matrix - 3
May 2, 2024
58093d3
Artifact + Matrix - 4
May 2, 2024
368900b
Artifact + Matrix - 5
May 3, 2024
bf3e9f7
Updated docker image tag in .env to the latest timestamp:
actions-user May 3, 2024
6eebf87
Updated docker image tag in .env to the latest timestamp: 2024-05-03-…
actions-user May 3, 2024
e760598
Added TODOs in github actions workflow YAML file
May 3, 2024
9444e60
Artifact + Matrix - 6
May 3, 2024
40beb80
Updated docker image tag in .env file to the latest timestamp
actions-user May 3, 2024
29ebf49
Updated docker image tag in .env file to the latest timestamp
actions-user May 3, 2024
1d0a937
Merge branch 'main' into image-push
nataliejschultz May 3, 2024
308eca0
Updated docker image tag in .env file to the latest timestamp
actions-user May 6, 2024
35e09cb
Merge branch 'image-push' into tags-combo-approach
nataliejschultz May 8, 2024
d919a34
Updated docker image tag in .env file to the latest timestamp
actions-user May 8, 2024
11cdafb
Cleanup image_build_push.yml
nataliejschultz May 8, 2024
1dda106
Polishing image_build_push.yml
nataliejschultz May 8, 2024
66bd0a6
Polishing fetch_runID.py
nataliejschultz May 8, 2024
426ae50
Merge branch 'image-push' into tags-combo-approach
nataliejschultz May 8, 2024
3b298fc
Merge pull request #11 from MukuFlash03/tags-combo-approach
nataliejschultz May 8, 2024
4335f39
Cert copy
nataliejschultz May 8, 2024
b330f96
Delete viz_scripts/docker/cert.sh
nataliejschultz May 8, 2024
9b1dca5
Merge branch 'main' into image-push
nataliejschultz May 8, 2024
ab0e157
Update docker-compose.yml
nataliejschultz May 21, 2024
7c78c18
Replacing docker build in image_build_push.yml with docker compose
nataliejschultz May 23, 2024
27c2f42
Delete .env
nataliejschultz May 23, 2024
c8b6dca
Remove whitespace changes to docker-compose.dev.yml
nataliejschultz May 23, 2024
40bf355
Removing redundant pip install
nataliejschultz May 23, 2024
803e9c2
Updating tag name
nataliejschultz May 23, 2024
7ee8e61
Adding artifact upload
nataliejschultz May 24, 2024
af3c2d3
Removing DB_HOST fallback in start_notebook.sh
nataliejschultz May 24, 2024
91d5251
DOCKER_IMAGE_TAG --> SERVER_IMAGE_TAG rename
nataliejschultz May 24, 2024
d3bf89f
Testing workflow
nataliejschultz May 26, 2024
c58b5dd
Testing workflow (again)
nataliejschultz May 26, 2024
14775b5
Push test + adding rename step
nataliejschultz May 26, 2024
f595b0d
dash to dot
nataliejschultz May 26, 2024
2f17e5d
change FROM context
nataliejschultz May 26, 2024
25dcba1
Reverting changes made to test
nataliejschultz May 26, 2024
82cf4e9
Switching to build prod instead of dev
nataliejschultz May 28, 2024
5d7f6d8
Modified tag variable names to be more relevant
Aug 13, 2024
cedf7b1
Updated username to clarify that env file is being updated
Aug 13, 2024
6849f84
Re-added .env file
Aug 14, 2024
f325eb3
Changing images to use docker-compose DEV file
Aug 14, 2024
eb4672c
Tag and Push frontend dashboard image only on Push event
Aug 14, 2024
e87058d
Hardcoded WEB_SERVER_HOST to 0.0.0.0
Aug 14, 2024
7483f2a
Changing to use non-dev version
Aug 14, 2024
2434648
Removing artifact method
Aug 14, 2024
29353b0
Merge branch 'main' into image-push
MukuFlash03 Aug 14, 2024
b98cf53
Added suffix to frontend image
Aug 14, 2024
8153155
Merge branch 'image-push' of https://github.com/MukuFlash03/em-public…
Aug 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/fetch_runID.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

import json
import logging
import requests
import sys

if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)

'''
Workflow "docker image" uses image_build_push.yml
From above commented out code, and checked via terminal as well,
workflow id for the "docker image" can be fetched using:
https://api.github.com/repos/MukuFlash03/e-mission-server/actions/workflows
https://api.github.com/repos/e-mission/e-mission-server/actions/workflows

For MukuFlash03: id = 75506902
For e-mission-server: id = 35580278
'''

download_url = "https://api.github.com/repos/e-mission/e-mission-server/actions/workflows/35580278/runs"
logging.debug("About to fetch workflow runs present in docker image workflow present in e-mission-server from %s" % download_url)
r = requests.get(download_url)
if r.status_code != 200:
logging.debug(f"Unable to fetch workflow runs, status code: {r.status_code}")
sys.exit(1)
else:
workflow_runs_json = json.loads(r.text)
logging.debug(f"Successfully fetched workflow runs")

workflow_runs = workflow_runs_json["workflow_runs"]
if workflow_runs:
successful_runs = [run for run in workflow_runs \
if run["status"] == "completed" and \
run["conclusion"] == "success" and \
run["head_branch"] == "main"
]
if successful_runs:
sorted_runs = successful_runs.sort(reverse=True, key=lambda x: x["updated_at"])
sorted_runs = sorted(successful_runs, reverse=True, key=lambda x: x["updated_at"])
latest_run_id = sorted_runs[0]["id"]
print(f"::set-output name=run_id::{latest_run_id}")
153 changes: 153 additions & 0 deletions .github/workflows/image_build_push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
name: docker-image-push-public-dash

on:
push:
branches: [ main ]

workflow_dispatch:
inputs:
docker_image_tag:
description: "Latest Docker image tags passed from e-mission-server repository on image build and push"
required: true

env:
DOCKER_USER: ${{secrets.DOCKER_USER}}
DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}

jobs:
fetch_run_id:
runs-on: ubuntu-latest

outputs:
run_id: ${{ steps.get_run_id.outputs.run_id }}

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'

- name: Install Python dependencies
run: |
pip install requests

- name: Run Python script
id: run_script
run: |
echo "Fetching latest successful run ID from e-misison-server docker image workflow"
python .github/fetch_runID.py

- name: Get Run ID
id: get_run_id
run: echo "run_id=${{ steps.run_script.outputs.run_id }}" >> "$GITHUB_OUTPUT"

fetch_tag:
needs: fetch_run_id
runs-on: ubuntu-latest

env:
RUN_ID: ${{ needs.fetch_run_id.outputs.run_id }}

outputs:
docker_image_tag: ${{ steps.get_docker_tag.outputs.docker_image_tag }}

steps:
- uses: actions/checkout@v4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, future fix: why are we checking this out twice?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on this, each job will need its own checkout/environment


- name: Use Run ID from previous fetch_run_id job
run: echo Run ID from previous job ${{ env.RUN_ID }}

- name: Download artifact
uses: actions/download-artifact@v4
with:
# TODO: Create a token with basic repo permissions
name: docker-image-tag
github-token: ${{ secrets.GH_PAT_TAG }}
repository: e-mission/e-mission-server
run-id: ${{ env.RUN_ID }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I don't think we need to download the artifact. We already have a .env file that has the last server image. Why do we need to do all the work of finding the last workflow and downloading the artifact instead of just using the .env file that is already checked in?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As highlighted in this comment in the documented issue, one of the final stages I had reached in designing the CI/CD was to eliminate having to manually update any docker tags (from a developer's perspective who will use the repos).

In the public-dash and admin-dash workflows, workflow dispatch directly receives it via input parameters, so it doesn't have to deal with artifacts.
But the push event is the one that utilizes the docker tags from the downloaded artifact.
The tag from this artifact is the one that is written to the .env file for every push event.


Now a few scenarios:

  1. What happens if a developer doesn't have .env file in their checkout out repo?
    The .env file would always be present once this PR has been merged.
    As a part of this PR, we are manually adding the .env file with the latest server image tag currently available in Dockerhub. This manual addition only needs to be done once during these code changes. Once implemented, the workflow will automatically update the .env file.
    Developers would then just pull in the remote changes and they should have the appropriate .env file.

  2. What happens if a developer changes the image tag in .env file?
    The workflow first executes the steps to fetch the latest tag from the server repo.
    Any existing tag in .env file will be overridden with this latest tag.
    This ensures two things:
    a. incorrect/non-existent tags will be overridden.
    b. latest server image is used always.


To summarize, no one would need to update the .env file, the workflow would do it automatically.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With that said, I do kind of see why we don't need to download the artifact.

Let's consider a few more scenarios:

  1. Workflow dispatch: Server image is updated and new version pushed.
    This will trigger the workflow dispatch which triggers workflows in the dashboard repos.
    This updates the .env file.
    The new tag is then used in building the image.

  1. Push event: Server image is not updated; dashboard repos have changes pushed.
    In the existing workflow, the push will download the artifact and overwrite the .env file.

But, the .env file already has the latest tag from when the workflow dispatch event occurred.
So, the push event can simply read in the latest server tag from the .env file.


- name: Print artifact tag
id: get_docker_tag
run: |
cat tag_file.txt
docker_image_tag=$(cat tag_file.txt)
echo $docker_image_tag
echo "docker_image_tag=$(echo $docker_image_tag)" >> $GITHUB_OUTPUT
build:
needs: fetch_tag

runs-on: ubuntu-latest

env:
DOCKER_IMAGE_TAG_1: ${{ needs.fetch_tag.outputs.docker_image_tag }}
DOCKER_IMAGE_TAG_2: ${{ github.event.inputs.docker_image_tag }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, future fix: better names

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarification: Better names for the environment variables?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, TAG_1 and TAG_2 are not meaningful names.


steps:
- uses: actions/checkout@v4

- name: Print input docker image tag
run: |
echo "Event name: ${{ github.event_name }}"
echo "Latest docker image tag (push): ${{ env.DOCKER_IMAGE_TAG_1 }}"
echo "Latest docker image tag (workflow_dispatch): ${{ env.DOCKER_IMAGE_TAG_2 }}"

- name: Update .env file
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "Workflow_dispatch: New server image built and pushed, Updating image tag in .env"
echo "DOCKER_IMAGE_TAG=$DOCKER_IMAGE_TAG_2" > .env
else
echo "Push event: Restoring latest server image tag in .env"
echo "DOCKER_IMAGE_TAG=$DOCKER_IMAGE_TAG_1" > .env
fi

- name: Add, Commit, Push changes to .env file
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, future fix: configure this to be more meaningful; "GitHub Action" doing what?

if git diff --quiet; then
echo "Latest timestamp already present in .env file, no changes to commit"
else
git add .env
git commit -m "Updated docker image tag in .env file to the latest timestamp"
git push origin
fi

- name: docker login
run: | # log into docker hub account
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD

- name: Get current date # get the date of the build
id: date
run: echo "::set-output name=date::$(date +'%Y-%m-%d--%M-%S')"

- name: Run a one-line script
run: echo running in repo ${GITHUB_REPOSITORY#*/} branch ${GITHUB_REF##*/} on ${{ steps.date.outputs.date }}

- name: build docker image
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
SERVER_IMAGE_TAG=$DOCKER_IMAGE_TAG_2 FRONTEND_TAG=$DOCKER_USER/${GITHUB_REPOSITORY#*/}:${GITHUB_REF##*/}_${{ steps.date.outputs.date }} VIZ_TAG=$DOCKER_USER/${GITHUB_REPOSITORY#*/}_notebook:${GITHUB_REF##*/}_${{ steps.date.outputs.date }} docker compose -f docker-compose.yml build
else
SERVER_IMAGE_TAG=$DOCKER_IMAGE_TAG_1 FRONTEND_TAG=$DOCKER_USER/${GITHUB_REPOSITORY#*/}:${GITHUB_REF##*/}_${{ steps.date.outputs.date }} VIZ_TAG=$DOCKER_USER/${GITHUB_REPOSITORY#*/}_notebook:${GITHUB_REF##*/}_${{ steps.date.outputs.date }} docker compose -f docker-compose.yml build
fi
docker images

- name: push docker image
run: |
docker push $DOCKER_USER/${GITHUB_REPOSITORY#*/}:${GITHUB_REF##*/}_${{ steps.date.outputs.date }}
docker push $DOCKER_USER/${GITHUB_REPOSITORY#*/}_notebook:${GITHUB_REF##*/}_${{ steps.date.outputs.date }}

- name: Create a text file
run: |
echo ${{ steps.date.outputs.date }} > public_dash_tag_file.txt
echo "Created tag text file"

- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: public-dash-image-tag
path: public_dash_tag_file.txt
overwrite: true
Comment on lines +93 to +103
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need this?

Copy link
Contributor

@nataliejschultz nataliejschultz Aug 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shankari the point of the artifact is to allow the internal repo to access the new tag outside of the run (see the internal repo PR and
commit 7ee8e61 )

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I still think we should be able to use tags and .env files instead, but will defer that discussion until the cleanup/polish

1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ celerybeat.pid
*.sage.py

# Environments
.env
.venv
env/
venv/
Expand Down
6 changes: 4 additions & 2 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ services:
notebook-server:
image: em-pub-dash-dev/viz-scripts
build:
context: viz_scripts
dockerfile: docker/Dockerfile.dev
context: viz_scripts
dockerfile: docker/Dockerfile.dev
args:
SERVER_IMAGE_TAG: ${SERVER_IMAGE_TAG}
Comment on lines +23 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the expectation that the user will set the SERVER_IMAGE_TAG or does this work to read from the .env file? How have you tested that this works?

Copy link
Contributor Author

@MukuFlash03 MukuFlash03 Aug 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the user will not be required to manually set the image tags at any point.
Unless they want to test other server image versions locally.

The args will be read in from the .env file.
I tested this locally by ensuring the .env file was present and had an image tag pointing to the correct server image.

It builds the image successfully.


.env file with the latest server image tag

SERVER_IMAGE_TAG=2024-08-12--15-15

Some logs from docker compose command:

$ docker-compose -f docker-compose.dev.yml  up

...
[+] Building 169.1s (21/21) FINISHED                                                              docker:desktop-linux
 => [notebook-server internal] load build definition from Dockerfile.dev                                          0.0s
 => => transferring dockerfile: 717B                                                                              0.0s
 => [dashboard internal] load build definition from Dockerfile.dev                                                0.0s
 => => transferring dockerfile: 178B                                                                              0.0s
 => [notebook-server internal] load metadata for docker.io/shankari/e-mission-server:master_2024-08-12--15-15     1.5s
 => [dashboard internal] load metadata for docker.io/library/node:21.7.2-alpine                                   1.6s
 => [notebook-server internal] load .dockerignore                                                                 0.0s
 => => transferring context: 2B                                                                                   0.0s
 => [dashboard internal] load .dockerignore                                                                       0.0s
 => => transferring context: 2B                                                                                   0.0s
 => [notebook-server 1/8] FROM docker.io/shankari/e-mission-server:master_2024-08-12--15-15@sha256:f05c128a8fe4  66.6s
...

depends_on:
- db
environment:
Expand Down
10 changes: 7 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: "3"
services:
dashboard:
image: em-pub-dash-prod/frontend
image: ${FRONTEND_TAG}
build: frontend
depends_on:
- db
Expand All @@ -13,8 +13,12 @@ services:
networks:
- emission
notebook-server:
image: em-pub-dash-prod/viz-scripts
build: viz_scripts
image: ${VIZ_TAG}
build:
context: viz_scripts
dockerfile: Dockerfile
args:
SERVER_IMAGE_TAG: ${SERVER_IMAGE_TAG}
depends_on:
- db
environment:
Expand Down
7 changes: 6 additions & 1 deletion viz_scripts/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# python 3
FROM shankari/e-mission-server:master_2024-05-06--36-33

ARG SERVER_IMAGE_TAG
FROM shankari/e-mission-server:master_${SERVER_IMAGE_TAG}

ADD https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem /etc/ssl/certs/


VOLUME /plots

Expand Down
4 changes: 3 additions & 1 deletion viz_scripts/docker/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# python 3
FROM shankari/e-mission-server:master_2024-05-06--36-33

ARG SERVER_IMAGE_TAG
FROM shankari/e-mission-server:master_${SERVER_IMAGE_TAG}

VOLUME /plots

Expand Down
5 changes: 2 additions & 3 deletions viz_scripts/docker/start_notebook.sh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that you should also remove the WEB_SERVER_HOST variable in this file since it is unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file does use this variable in setting the PYTHONPATH.

if [ -z ${CRON_MODE} ] ; then
    echo "Running notebook in docker, change host:port to localhost:47962 in the URL below"
    PYTHONPATH=/usr/src/app jupyter notebook --no-browser --ip=${WEB_SERVER_HOST} --allow-root
else

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
echo "DB host = "${DB_HOST}
if [ -z ${DB_HOST} ] ; then
local_host=`hostname -i`
sed "s-localhost-${local_host}_" conf/storage/db.conf.sample > conf/storage/db.conf
else
sed "s-localhost-${DB_HOST}-" conf/storage/db.conf.sample > conf/storage/db.conf
export DB_HOST=$local_host
echo "Setting db host environment variable to localhost"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, future fix: this can be removed and simplified (similar to e-mission/e-mission-server#961 (comment))

fi

### configure the saved-notebooks directory for persistent notebooks
Expand Down