Skip to content

Repository files navigation

termai-cicd

CI/CD testing project for Termai, using a simple FastAPI service with one endpoint:

  • GET /health returns status and time (Australia/Sydney ISO-8601 format).

Requirements

  • Python 3.11+

Install

python -m venv .venv

Windows PowerShell:

.venv\Scripts\Activate.ps1

macOS/Linux:

source .venv/bin/activate

Install app and test dependencies:

python -m pip install --upgrade pip
python -m pip install -e ".[test,dev]"

Build / Checks

Compile source and tests:

python -m compileall app tests

Run tests:

python -m pytest -q

Run tests with info

python -m pytest -vv -s -rA --log-cli-level=INFO

Run Service

Start FastAPI with Uvicorn:

uvicorn app.main:app --host 0.0.0.0 --port 8101 --reload

Health endpoint:

curl http://127.0.0.1:8101/health

Local Docker Testing

Build the image:

$RAW_VERSION = python -m setuptools_scm
$VERSION = $RAW_VERSION.Trim() -replace '\+', '-'
docker build -t "termai-cicd:$VERSION" -t "termai-cicd:latest" .

Run the container:

docker run --rm -p 8101:8101 --name termai-cicd-local "termai-cicd:$VERSION"

Test the health endpoint from another terminal:

curl http://127.0.0.1:8101/health

Inspect logs:

docker logs termai-cicd-local

Stop the container:

docker stop termai-cicd-local

CI/CD Pipeline

The GitHub Actions workflow at .github/workflows/ci.yml runs on every push to main and performs:

  1. Python setup and dependency installation from requirements.txt and requirements-test.txt.
  2. Unit/integration test execution with pytest.
  3. Docker image build.
  4. Image push to GitHub Container Registry (GHCR) with tags:
    • ghcr.io/<owner>/<repo>:<commit-sha>
    • ghcr.io/<owner>/<repo>:latest

Required GitHub setup:

  • Repository Actions must have packages: write permission.
  • Registry auth is handled with ${{ secrets.GITHUB_TOKEN }} in the workflow.

Dynamic version tags are sanitized for Docker compatibility (replaces + with -):

raw_version="$(python -m setuptools_scm)"
docker_version="${raw_version//+/-}"
echo "value=$docker_version" >> "$GITHUB_OUTPUT"

The workflow outputs docker_version and uses it for image tags.

Git Tag And Release Versioning

Project versioning is managed by setuptools-scm from git history/tags.

  • On a tagged commit (for example v0.2.0), the package version is 0.2.0.
  • On commits after that tag, versions are generated automatically (for example 0.2.0.post1+g<sha>).

Create a new release tag:

git checkout main
git pull
git tag -a v0.2.0 -m "Release v0.2.0"
git push origin v0.2.0

Create a GitHub release from the tag:

gh release create v0.2.0 --title "v0.2.0" --notes "Release notes for v0.2.0"

Recommended release flow:

  1. Merge tested changes to main.
  2. Create and push an annotated tag (vX.Y.Z).
  3. Create a GitHub release for that tag.
  4. Let CI build/push the Docker image for the tagged commit.

Kubernetes Deploy

Manifests are under k8s/:

  • deployment.yaml
  • service.yaml
  • ingress.yaml (TLS enabled; uses secret termai-cicd-tls)

These files use placeholders so namespace/image/host are configurable:

  • ${NAMESPACE}
  • ${IMAGE}
  • ${INGRESS_HOST}

Apply them with envsubst:

export NAMESPACE=termai
export IMAGE=ghcr.io/<owner>/<repo>:<commit-sha>
export INGRESS_HOST=termai.internal.example.com

kubectl create namespace "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f -
envsubst < k8s/deployment.yaml | kubectl apply -f -
envsubst < k8s/service.yaml | kubectl apply -f -
envsubst < k8s/ingress.yaml | kubectl apply -f -

For .dw.csiro.au, cert-manager will provision TLS automatically from the Ingress annotation:

cert-manager.io/cluster-issuer: cluster-issuer-csiro

termai-cicd-tls is created/renewed by cert-manager.

Verify HTTPS:

curl -I https://termai-cicd.dw.csiro.au/health

Updating Image And Triggering Deployment

  1. Push code to main to trigger CI and publish a new image tag (commit SHA).
  2. Update deployment to the new image:
export NAMESPACE=termai
export IMAGE=ghcr.io/<owner>/<repo>:<new-commit-sha>
envsubst < k8s/deployment.yaml | kubectl apply -f -
kubectl -n "$NAMESPACE" rollout status deploy/termai-cicd

Suggested Project Structure

.
├── app/                         # FastAPI application code
├── tests/                       # Pytest test suite
├── Dockerfile                   # Container build definition
├── .dockerignore
├── requirements.txt             # Runtime dependencies
├── requirements-test.txt        # Test dependencies
├── k8s/                         # Kubernetes manifests
│   ├── deployment.yaml
│   ├── service.yaml
│   └── ingress.yaml
└── .github/
    └── workflows/
        └── ci.yml               # CI pipeline (test, build, push)

About

A test project for implementing CI/CD pipelines with GitHub and deploying applications to an internal Kubernetes cluster.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages