Skip to content

Commit

Permalink
Merge pull request #1 from PlanktoScope/feature/build-docker
Browse files Browse the repository at this point in the history
Add a GitHub Actions workflow to build the Docker container image
  • Loading branch information
ethanjli authored Apr 29, 2024
2 parents b582d40 + 7234dc0 commit a83b7ea
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 8 deletions.
142 changes: 142 additions & 0 deletions .github/workflows/build-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
name: Build Docker container image

on:
push:
branches:
- 'main'
- 'beta'
- 'stable'
tags:
- 'v*'
pull_request:
merge_group:
workflow_dispatch:
inputs:
git-ref:
description: 'Git ref (optional)'
required: false

env:
REGISTRY_IMAGE: ghcr.io/planktoscope/streamlit-classification-app

jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4

- name: Prepare environment variables
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
# Build and publish Docker container image
- name: Get Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=sha
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push by digest
id: build
uses: docker/build-push-action@v5
with:
context: ./
pull: true
push: ${{ (github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork) || github.event_name == 'push' || github.event_name == 'push tag' }}
platforms: ${{ matrix.platform }}
tags: ${{ env.REGISTRY_IMAGE }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=build-${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=build-${{ matrix.platform }}
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=${{ !github.event.pull_request.head.repo.fork }}

- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1

merge:
runs-on: ubuntu-latest
needs:
- build
permissions:
contents: read
packages: write
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true

# Build and publish Docker container image
- name: Get Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=match,pattern=v(.*),group=1
type=edge,branch=main
type=ref,event=branch,enable=${{ github.ref != format('refs/heads/{0}', 'main') && github.ref != format('refs/heads/{0}', 'main') }}
type=ref,event=pr
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'stable') }}
type=sha
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
if: ${{ (github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork) || github.event_name == 'push' || github.event_name == 'push tag' }}
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Create manifest list and push
working-directory: /tmp/digests
if: ${{ (github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork) || github.event_name == 'push' || github.event_name == 'push tag' }}
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Inspect image
if: ${{ (github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork) || github.event_name == 'push' || github.event_name == 'push tag' }}
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}
22 changes: 16 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Use an official Python runtime as the base image
FROM python:3.12
# We use the same base image as what the PlanktoScope segmenter's container image uses:
FROM docker.io/library/python:3.9.18-slim-bullseye

# Install curl for container healthcheck
RUN \
apt-get update && \
apt-get -y upgrade && \
apt-get -y install --no-install-recommends curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
rm -f /tmp/apt-packages

# Set the working directory in the container
WORKDIR /app
Expand All @@ -8,16 +18,16 @@ WORKDIR /app
COPY . .

# Install the required dependencies
RUN pip3 install -r requirements.txt
RUN \
pip3 install -r requirements.txt --index-url https://download.pytorch.org/whl/cpu --extra-index-url https://pypi.org/simple && \
pip3 cache purge && \
rm -rf /root/.cache/pip

# Make port 8501 available to anyone outside this container
EXPOSE 8501

# Add a healthcheck to the container
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health

# Set the command to run the Streamlit app (what the image will do when it starts as a container)
#CMD ["streamlit", "run", "app_model.py"]

# Run the Streamlit app
ENTRYPOINT ["streamlit", "run", "app_model.py", "--server.port=8501", "--server.address=0.0.0.0"]
ENTRYPOINT ["streamlit", "run", "app_model.py", "--server.port=8501", "--server.address=0.0.0.0", "--server.headless=true"]
6 changes: 6 additions & 0 deletions forklift-repository.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
forklift-version: v0.7.0

repository:
path: github.com/PlanktoScope/streamlit-classification-app
description: Forklift package for the PlanktoScope OS
readme-file: README.md
17 changes: 17 additions & 0 deletions pkg/compose-frontend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
services:
server:
networks:
- caddy-ingress
labels:
caddy: :80
caddy.redir: /ps/streamlit-demo /ps/streamlit-demo/
caddy.handle_path: /ps/streamlit-demo/*
caddy.handle_path.reverse_proxy: "{{upstreams 8501}}"
environment:
STREAMLIT_SERVER_BASE_URL_PATH: /ps/streamlit-demo
healthcheck:
test: curl --fail http://localhost:8501/ps/streamlit-demo/_stcore/health || exit 1

networks:
caddy-ingress:
external: true
8 changes: 8 additions & 0 deletions pkg/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
services:
server:
image: ghcr.io/planktoscope/streamlit-classification-app:sha-0703263

networks:
default:
name: none
external: true
33 changes: 33 additions & 0 deletions pkg/forklift-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package:
description: Demo app with a pre-trained demo model for classifying segmented objects
maintainers:
# Note: this is the maintainer of the Forklift package, not the maintainer of the app itself
- name: Ethan Li
email: [email protected]
license: Apache-2.0
sources:
- https://github.com/PlanktoScope/streamlit-classification-app

deployment:
compose-files: [compose.yml]

features:
frontend:
description: Provides access to a browser landing page
compose-files: [compose-frontend.yml]
requires:
networks:
- description: Overlay network for Caddy to connect to upstream services
name: caddy-ingress
services:
- tags: [caddy-docker-proxy]
port: 80
protocol: http
provides:
services:
- description: PlanktoScope documentation site
port: 80
protocol: http
paths:
- /ps/streamlit-demo
- /ps/streamlit-demo/*
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
streamlit
opencv-python
opencv-python-headless==4.6.0.66
numpy
seaborn
matplotlib
plotly
Pillow
torch
torchvision
torchvision

0 comments on commit a83b7ea

Please sign in to comment.