Overview
Penn Labs uses an automated deployment pipeline that flows from GitHub Actions through Kraken and Kittyhawk to Kubernetes. This guide explains how deployments work and what’s required to deploy applications.Deployment Pipeline
The deployment pipeline consists of four main stages:1. GitHub Actions
When code is pushed to themaster branch, GitHub Actions workflows automatically trigger. These workflows are generated using CDKActions and configured in .github/cdk/.
For most Penn Labs applications using the standard Django + React structure, the workflow:
- Lints and tests the code
- Builds Docker images for backend and frontend
- Publishes images to Docker Hub
- Triggers the deployment job
AWS_ACCOUNT_ID- AWS account ID for EKS clusterGH_AWS_ACCESS_KEY_ID- AWS access key for GitHub Actions userGH_AWS_SECRET_ACCESS_KEY- AWS secret key for GitHub Actions userDOCKERHUB_TOKEN- Token for publishing to Docker Hub
2. Kraken
Kraken is a CDKActions library that configures GitHub Actions workflows. It provides:LabsApplicationStack- Pre-configured CI/CD for Django + React projectsDeployJob- Handles the deployment processDjangoProjectandReactProject- Individual project configurations
cdk/kraken/ and generates the workflow YAML files.
Key Features:
- Automatically runs tests before deploying
- Only deploys from the master branch
- Sets environment variables like
GIT_SHAfor image tags
3. Kittyhawk
Kittyhawk is an automated Kubernetes YAML generator built on CDK8s. It allows you to define deployment configurations in TypeScript using constructs. Common Constructs:ReactApplication- Frontend React appsDjangoApplication- Backend Django appsRedisApplication- Redis instancesCronJob- Scheduled jobs
DeployJob in Kraken runs the following steps:
-
Synth manifests - Generate Kubernetes YAML from TypeScript:
-
Deploy - Apply manifests to Kubernetes:
k8s/dist/ but are not committed to the repository.
4. Kubernetes (EKS)
The final stage applies the manifests to the production EKS cluster: Cluster Details:- Name:
production - Region:
us-east-1 - Version: 1.23
- Node Type: r5d.xlarge (SPOT instances)
- Network: Prefix delegation enabled for more IPs per node
- Certificates are applied first (if any)
- All resources with the application label are applied
- The
--pruneflag removes resources that are no longer defined
IAM Permissions
The GitHub Actions user needs specific IAM permissions to deploy: Required Policies:kubectl- Assume the kubectl IAM roleview-eks- Describe EKS cluster to get connection info
kubectl role is defined in terraform/eks.tf and can be assumed by:
- SRE team members
- GitHub Actions user (
gh-actions) - Bastion instance
Deployment Configuration
Setting Up a New Project
-
Create CDKActions config in
.github/cdk/: -
Create Kittyhawk config in
k8s/main.ts: -
Build the GitHub Actions workflows:
Monitoring Deployments
After pushing to master:- Check GitHub Actions - View workflow progress in the Actions tab
- Verify pods are running:
- Check pod logs:
- Monitor in Grafana - Use the Pod Dashboard to see deployment status
Common Issues
Image Pull Errors
Symptom:ImagePullBackOff errors
Solution: Ensure docker-pull-secret exists in the namespace:
Secret Not Found
Symptom: Pods fail to start with secret errors Solution: Check that secrets are synced from Vault:Certificate Issues
Symptom: TLS/HTTPS not working Solution: Check certificate status:Best Practices
- Always run tests locally before pushing to master
- Use semantic versioning for Docker image tags when needed
- Review generated YAML locally with
yarn buildink8s/before pushing - Monitor deployments in real-time through GitHub Actions and Grafana
- Set appropriate replica counts based on load (typically 2 for redundancy)
- Use resource limits to prevent pods from consuming too many resources