7.8 KiB
APRS Repository Setup for Kubernetes Deployment
This document provides instructions for setting up your Elixir/Phoenix APRS repository to build Docker images and deploy to your K3s cluster on GitHub Actions push to main branch.
Prerequisites
- GitHub repository for your APRS application
- GitHub Container Registry (ghcr.io) access
- Tailscale installed on your K3s nodes
- Tailscale OAuth client for GitHub Actions
Steps to Configure Your APRS Repository
1. Create Dockerfile
Add this Dockerfile to the root of your APRS repository:
# Build stage
FROM elixir:1.15-alpine AS build
# Install build dependencies
RUN apk add --no-cache build-base git python3
# Set build env
ENV MIX_ENV=prod
# Install hex + rebar
RUN mix local.hex --force && \
mix local.rebar --force
# Set build directory
WORKDIR /app
# Copy mix files
COPY mix.exs mix.lock ./
COPY config config
# Install dependencies
RUN mix deps.get --only $MIX_ENV
RUN mix deps.compile
# Copy app files
COPY priv priv
COPY lib lib
COPY assets assets
# Compile assets
RUN mix assets.deploy
# Compile the release
RUN mix compile
# Build release
RUN mix release
# Runtime stage
FROM alpine:3.18 AS runtime
# Install runtime dependencies
RUN apk add --no-cache libstdc++ openssl ncurses-libs
WORKDIR /app
# Create non-root user
RUN addgroup -g 1000 -S aprs && \
adduser -u 1000 -S aprs -G aprs
# Copy release from build stage
COPY --from=build --chown=aprs:aprs /app/_build/prod/rel/aprs ./
# Add health check endpoint if not already present
USER aprs
ENV HOME=/app
ENV MIX_ENV=prod
ENV PORT=4000
ENV PHX_SERVER=true
EXPOSE 4000
CMD ["bin/aprs", "start"]
2. Create GitHub Actions Workflow
Create .github/workflows/deploy.yml in your APRS repository:
name: Build and Deploy
on:
push:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Setup Tailscale
uses: tailscale/github-action@v2
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:ci
- name: Set kubeconfig
run: |
mkdir -p ~/.kube
echo "${{ secrets.TAILSCALE_KUBECONFIG }}" | base64 -d > ~/.kube/config
# Replace the K3s master IP with its Tailscale IP
sed -i 's/server: https:\/\/[0-9.]*:6443/server: https:\/\/${{ secrets.K3S_TAILSCALE_IP }}:6443/g' ~/.kube/config
- name: Deploy to K3s
run: |
kubectl set image deployment/aprs aprs=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} -n aprs
- name: Wait for rollout
run: |
kubectl rollout status deployment/aprs -n aprs
3. Configure Health Check Endpoint
Add a health check endpoint to your Phoenix application if not already present:
# In your router (lib/aprs_web/router.ex)
scope "/", AprsWeb do
pipe_through :browser
get "/health", HealthController, :index
# ... other routes
end
Create the health controller:
# lib/aprs_web/controllers/health_controller.ex
defmodule AprsWeb.HealthController do
use AprsWeb, :controller
def index(conn, _params) do
json(conn, %{status: "ok"})
end
end
4. Update Production Configuration
Ensure your config/runtime.exs includes:
import Config
if config_env() == :prod do
database_url =
System.get_env("DATABASE_URL") ||
raise """
environment variable DATABASE_URL is missing.
"""
config :aprs, Aprs.Repo,
url: database_url,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
socket_options: [:inet6]
secret_key_base =
System.get_env("SECRET_KEY_BASE") ||
raise """
environment variable SECRET_KEY_BASE is missing.
"""
host = System.get_env("PHX_HOST") || "example.com"
port = String.to_integer(System.get_env("PORT") || "4000")
config :aprs, AprsWeb.Endpoint,
url: [host: host, port: 443, scheme: "https"],
http: [
ip: {0, 0, 0, 0},
port: port
],
secret_key_base: secret_key_base
config :aprs, AprsWeb.Endpoint, server: true
end
5. Setup Tailscale OAuth Client
- Go to https://login.tailscale.com/admin/settings/oauth
- Create a new OAuth client with these settings:
- Description: "GitHub Actions CI"
- Tags:
tag:ci - Capabilities: Read-only access
- Save the Client ID and Secret
6. Setup GitHub Secrets
In your APRS GitHub repository settings, add these secrets:
TS_OAUTH_CLIENT_ID: Your Tailscale OAuth client IDTS_OAUTH_SECRET: Your Tailscale OAuth client secretK3S_TAILSCALE_IP: The Tailscale IP of your K3s master node (get it withtailscale ip -4on the master)TAILSCALE_KUBECONFIG: Your K3s cluster kubeconfig file content (base64 encoded)# On your K3s server: sudo cat /etc/rancher/k3s/k3s.yaml | base64 -w0
7. Update Kubernetes Deployment Image
After your first GitHub Actions run, update the image in the Kubernetes deployment to use your actual GitHub username:
# In the infra repository
sed -i 's/YOUR_GITHUB_USERNAME/your-actual-username/g' clusters/aprs/aprs-deployment.yaml
8. Generate Secrets
Before deploying to Kubernetes, generate proper secrets:
# Generate a 64-character secret key base
mix phx.gen.secret
# Generate a strong PostgreSQL password
openssl rand -base64 32
Update the secrets.yaml file with these values before applying to your cluster.
9. Install Tailscale on K3s Nodes
Before deploying, ensure Tailscale is installed on your K3s nodes:
# From the ansible directory
export TAILSCALE_KEY="your-tailscale-auth-key"
ansible-playbook k3s-tailscale.yml
10. Apply Initial Deployment
# From the infra repository
kubectl apply -k clusters/aprs/
SSL Proxy Configuration
Since the APRS service is only accessible from the 10.0.16.0/22 network, you'll need to set up an external SSL proxy. Here's an example nginx configuration:
server {
listen 443 ssl http2;
server_name aprs.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://10.0.16.x:4000; # Replace with actual service IP
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Monitoring and Troubleshooting
Check deployment status:
kubectl get all -n aprs
kubectl logs -n aprs deployment/aprs
kubectl logs -n aprs deployment/postgis
Notes
- The PostGIS database will persist data in the PersistentVolume
- The APRS application runs with 2 replicas for high availability
- Resource limits are set conservatively; adjust based on your needs
- Remember to backup your PostGIS data regularly