Skip to content

Commit 194051d

Browse files
committed
Working pipeline and docs
1 parent 712e23e commit 194051d

21 files changed

+1018
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Build, Test, Run
2+
on:
3+
push:
4+
branches: [ main ]
5+
pull_request:
6+
branches: [ main ]
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- name: Setup Go
14+
uses: actions/setup-go@v5
15+
with:
16+
go-version: '1.25.2'
17+
- name: Install dependencies
18+
run: go get .
19+
- name: Build
20+
run: go build -v ./...
21+
- name: Test with the Go CLI
22+
run: go test ./...
23+
24+
lint:
25+
needs: [test]
26+
name: Lint
27+
runs-on: ubuntu-latest
28+
timeout-minutes: 3
29+
steps:
30+
- uses: actions/checkout@v4
31+
with:
32+
fetch-depth: 1
33+
- name: Setup Go
34+
uses: actions/setup-go@v5
35+
with:
36+
go-version: '1.25.2'
37+
- name: Install golangci-lint
38+
run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
39+
- name: Run golangci-lint
40+
run: golangci-lint run ./...
41+
42+
docker-build-and-push:
43+
needs: [test, lint]
44+
runs-on: ubuntu-latest
45+
steps:
46+
- name: Login to Docker Hub
47+
uses: docker/login-action@v3
48+
with:
49+
username: ${{ vars.DOCKER_USERNAME }}
50+
password: ${{ secrets.DOCKERHUB_TOKEN }}
51+
52+
- name: Set up Docker Buildx
53+
uses: docker/setup-buildx-action@v3
54+
55+
- name: Build and push
56+
uses: docker/build-push-action@v6
57+
with:
58+
platforms: linux/amd64,linux/arm64
59+
push: true
60+
tags: ${{ vars.DOCKER_USERNAME }}/${{ github.event.repository.name }}:latest
61+
62+
deploy-and-validate:
63+
needs: [test, lint, docker-build-and-push]
64+
runs-on: ubuntu-latest
65+
steps:
66+
- uses: actions/checkout@v4
67+
68+
- name: Create Kind cluster
69+
uses: helm/kind-action@v1.8.0
70+
with:
71+
cluster_name: ci-cluster-example
72+
wait: 120s
73+
74+
- name: Export kubeconfig
75+
run: |
76+
echo "Verifying Kind cluster setup..."
77+
mkdir -p $HOME/.kube
78+
kind get kubeconfig --name ci-cluster-example > $HOME/.kube/config
79+
echo "KUBECONFIG=$HOME/.kube/config" >> $GITHUB_ENV
80+
kubectl config use-context kind-ci-cluster-example
81+
kubectl cluster-info
82+
83+
- name: Set up Kubectl
84+
uses: azure/setup-kubectl@v3
85+
with:
86+
version: 'latest'
87+
88+
- name: Install Helm
89+
uses: azure/setup-helm@v1
90+
with:
91+
version: 'latest'
92+
93+
- name: Deploy to Kind cluster using Helm
94+
run: |
95+
helm upgrade --install pipeline-example ./pipeline-example --set image.repository=mbts89/pipeline_example --set image.tag=latest
96+
kubectl rollout status deployment/pipeline-example --timeout=90s
97+
- name: Test API endpoint
98+
run: |
99+
echo "Waiting for service to be ready..."
100+
kubectl wait --for=condition=available --timeout=90s deployment/pipeline-example
101+
echo "Starting port-forward..."
102+
kubectl port-forward deployment/pipeline-example 8080:8080 &
103+
sleep 5
104+
echo "Testing API response:"
105+
curl -s http://localhost:8080 | tee result.txt
106+
grep -q "Hello World" result.txt && echo "✅ API returned expected response" || (echo "❌ Unexpected API response" && exit 1)
107+
108+
- name: Start tMate Session
109+
uses: mxschmitt/action-tmate@v3
110+
with:
111+
limit-access-to-actor: true

.github/workflows/cleanup.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Cleanup the cluster
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
cleanup-kind:
8+
runs-on: ubuntu-latest
9+
env:
10+
CLUSTER_NAME: ci-cluster-example
11+
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v4
15+
16+
- name: Install Kind
17+
run: |
18+
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.23.0/kind-linux-amd64
19+
chmod +x ./kind
20+
sudo mv ./kind /usr/local/bin/kind
21+
22+
- name: Delete Kind cluster
23+
run: |
24+
kind delete cluster
25+
if kind get clusters | grep -q "$CLUSTER_NAME"; then
26+
echo "🧹 Deleting Kind cluster: $CLUSTER_NAME"
27+
kind delete cluster --name "$CLUSTER_NAME"
28+
else
29+
echo "✅ No existing cluster named $CLUSTER_NAME found — nothing to delete."
30+
fi
31+
32+
- name: Verify cleanup
33+
run: |
34+
echo "🔍 Checking clusters:"
35+
kind get clusters || echo "✅ Cleanup complete — no clusters remain."

Dockerfile

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
# FROM golang:1.25.2
3+
4+
# # Set destination for COPY
5+
# WORKDIR /app
6+
7+
# # Download Go modules
8+
# COPY go.mod ./
9+
# RUN go mod download
10+
11+
# # Copy the source code. Note the slash at the end, as explained in
12+
# # https://docs.docker.com/reference/dockerfile/#copy
13+
# COPY *.go ./
14+
15+
# # Build
16+
# RUN CGO_ENABLED=0 GOOS=linux go build -o /pipeline-example
17+
18+
# # Optional:
19+
# # To bind to a TCP port, runtime parameters must be supplied to the docker command.
20+
# # But we can document in the Dockerfile what ports
21+
# # the application is going to listen on by default.
22+
# # https://docs.docker.com/reference/dockerfile/#expose
23+
# EXPOSE 8080
24+
25+
# # Run
26+
# CMD ["go run main.go"]
27+
28+
FROM golang:1.25.2 AS builder
29+
30+
WORKDIR /app
31+
32+
# Copy the Go module files
33+
COPY go.mod .
34+
# COPY go.sum .
35+
36+
# Download the Go module dependencies
37+
RUN go mod download
38+
39+
COPY . .
40+
41+
# RUN go build -o myapp main.go
42+
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o myapp main.go
43+
44+
# Run the tests in the container
45+
FROM builder AS run-test-stage
46+
RUN go test -v ./...
47+
48+
49+
# FROM alpine:latest as run
50+
FROM alpine:latest
51+
WORKDIR /app
52+
COPY --from=builder /app/myapp .
53+
54+
# Copy the application executable from the build image
55+
# COPY *.go ./
56+
57+
WORKDIR /app
58+
EXPOSE 8080
59+
CMD ["./myapp"]
60+

README copy.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# pipeline-example
2+
3+
example for jamf
4+
docker desktop
5+
run in kind
6+
kind create cluster --name local-test
7+
8+
kubectl get pods
9+
10+
# 🧩 Basic API Pipeline Example
11+
12+
_A lightweight Go web service with automated Kubernetes deployment using Kind, Helm, and GitHub Actions._
13+
14+
---
15+
16+
## 📘 Overview
17+
18+
This repository demonstrates a full CI/CD workflow for a simple Go-based API deployed to a local **Kind (Kubernetes in Docker)** cluster.
19+
The GitHub Actions pipeline handles building, pushing, deploying, and verifying your application end-to-end — making it easy to reproduce locally or debug via **tmate**.
20+
21+
---
22+
23+
## What's it do?
24+
25+
A minimal Go API running on port `8080`:
26+
27+
```go
28+
func main() {
29+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
30+
fmt.Fprint(w, "Hello World")
31+
})
32+
http.ListenAndServe(":8080", nil)
33+
}
34+
```
35+
36+
When running, http://localhost:8080
37+
38+
⚙️ Prerequisites
39+
40+
Install these tools locally to mirror the CI environment:
41+
Tool - Version - Install
42+
Go ≥ 1.22 - golang.org/dl
43+
Docker ≥ 24 - docs.docker.com (I use Docker Desktop)
44+
Kubectl ≥ 1.30 - kubernetes.io
45+
Helm ≥ 3.14 - helm.sh
46+
Kind ≥ 0.23 - kind.sigs.k8s.io
47+
48+
# Running the App Locally
49+
50+
## Run locally
51+
52+
Pull the repo down and cd into it then run it locally to verify it works
53+
54+
```
55+
go run main.go
56+
```
57+
58+
## The included workflow automates the full build → deploy → verify cycle.
59+
60+
## Make sure Kubernetes is enabled in Docker
61+
62+
📄 .github/workflows/ci.yml
63+
Pipeline steps:
64+
Build & Test Go App
65+
Build & Push Docker Image — Builds and pushes to Docker Hub.
66+
Create Kind Cluster — Spins up a temporary Kubernetes cluster inside GitHub Actions.
67+
Export kubeconfig — Ensures Helm and kubectl point to the correct cluster.
68+
Deploy Helm Chart
69+
Verify API Response — Uses kubectl port-forward + curl to confirm Hello World.
70+
(Optional) action-tmate — Opens a live debugging session for interactive testing. [link](https://github.com/mxschmitt/action-tmate?tab=readme-ov-file)
71+
72+
🔐 Required GitHub Infp
73+
Name Description
74+
DOCKERHUB_USERNAME - Your Docker Hub username (new variable)
75+
DOCKERHUB_TOKEN - Docker Hub access token for docker push (new secret)
76+
Public SSH Key - Optional, for tMate validation
77+
78+
# Trigger Workflow
79+
80+
1. Make a change to a file and push it up to Github. Create a new PR and the workflow will kick off.
81+
82+
- When the workflow gets to the 'deploy-and-validate' stage, click into the workflow details.
83+
- Inside, wait for 'Start tMate Session' to start
84+
85+
- Click in, and wait for a series of ssh code to show up, should look similar to:
86+
🔹 How to Connect
87+
When the workflow reaches the tmate step, it prints something like:
88+
SSH: ssh abcdefgh@nyc1.tmate.io
89+
90+
SSH URL: Connect from your local terminal:
91+
`ssh abcdefgh@nyc1.tmate.io`
92+
93+
- 🔹 Once Inside tmate
94+
Check your pods:
95+
`kubectl get pods`
96+
97+
Run: `kubectl port-forward deployment/pipeline-example 9091:8080 &`
98+
Wait a couple of seconds, then run: `curl http://localhost:9091`
99+
100+
You should see a 'Hello World' returned to you.
101+
To close the instance, run `exit`. This will also finish your pipeline.
102+
You the pipeline will continue to run until you cancel it you dont use the tMate option.
103+
104+
🧹 Cleanup
105+
To reset your environment:
106+
kind delete cluster --name local-test
107+
docker image rm USERNAME/pipeline_example:latest
108+
109+
🔍 Troubleshooting
110+
Issue - Cause - Fix
111+
`port already in use` - Existing forward active `pkill -f "kubectl port-forward"`
112+
113+
## Structure
114+
115+
```.
116+
├── main.go
117+
├── Dockerfile
118+
├── pipeline-example/
119+
│ └─
120+
│ ├── Chart.yaml
121+
│ ├── templates/
122+
│ │ ├── deployment.yaml
123+
│ │ └── service.yaml
124+
│ └── values.yaml
125+
└── .github/
126+
└── workflows/
127+
└── ci.yml
128+
```
129+
130+
🏁 Summary
131+
132+
This project is a simple, reproducible template for:
133+
Building and deploying a Go API to Kubernetes.
134+
Managing deployments with Helm.
135+
Automating CI/CD with GitHub Actions.
136+
Debugging live clusters with action-tmate.

compose.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
version: "3.9"
2+
3+
services:
4+
pipeline-example:
5+
build:
6+
context: .
7+
dockerfile: Dockerfile
8+
container_name: pipeline-example
9+
ports:
10+
- "8080:8080"
11+
environment:
12+
HELLO_NAME: "Annie"
13+
healthcheck:
14+
test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
15+
interval: 10s
16+
timeout: 3s
17+
retries: 3
18+
restart: unless-stopped

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module hello-api
2+
3+
go 1.25.2

kind

10.7 MB
Binary file not shown.

0 commit comments

Comments
 (0)