Skip to content

Commit f1aea28

Browse files
committed
Add Docker and Kubernetes deployment configuration
- Dockerfile using ARO buildsystem and runtime images - Kubernetes manifests (deployment, service, ingress, kustomization) - GitHub Actions workflow for building and pushing to ghcr.io
1 parent 6985ae4 commit f1aea28

8 files changed

Lines changed: 315 additions & 0 deletions

File tree

.dockerignore

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Build artifacts
2+
.build/
3+
StatusPost
4+
5+
# IDE
6+
.idea/
7+
.vscode/
8+
*.swp
9+
10+
# Git
11+
.git/
12+
.gitignore
13+
14+
# Documentation
15+
README.md
16+
17+
# Deployment (not needed in image)
18+
deployment/
19+
Dockerfile
20+
.dockerignore

.github/workflows/build.yaml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Build and Push
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
tags:
8+
- 'v*'
9+
pull_request:
10+
branches:
11+
- main
12+
13+
env:
14+
REGISTRY: ghcr.io
15+
IMAGE_NAME: ${{ github.repository }}
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
permissions:
21+
contents: read
22+
packages: write
23+
24+
steps:
25+
- name: Checkout repository
26+
uses: actions/checkout@v4
27+
28+
- name: Set up Docker Buildx
29+
uses: docker/setup-buildx-action@v3
30+
31+
- name: Log in to Container Registry
32+
if: github.event_name != 'pull_request'
33+
uses: docker/login-action@v3
34+
with:
35+
registry: ${{ env.REGISTRY }}
36+
username: ${{ github.actor }}
37+
password: ${{ secrets.GITHUB_TOKEN }}
38+
39+
- name: Extract metadata (tags, labels)
40+
id: meta
41+
uses: docker/metadata-action@v5
42+
with:
43+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
44+
tags: |
45+
type=ref,event=branch
46+
type=ref,event=pr
47+
type=semver,pattern={{version}}
48+
type=semver,pattern={{major}}.{{minor}}
49+
type=sha,prefix=
50+
51+
- name: Build and push Docker image
52+
uses: docker/build-push-action@v5
53+
with:
54+
context: .
55+
push: ${{ github.event_name != 'pull_request' }}
56+
tags: ${{ steps.meta.outputs.tags }}
57+
labels: ${{ steps.meta.outputs.labels }}
58+
cache-from: type=gha
59+
cache-to: type=gha,mode=max

Dockerfile

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# =============================================================================
2+
# StatusPost - Multi-stage Docker Build
3+
# =============================================================================
4+
# Uses ARO buildsystem to compile, then ARO runtime to execute
5+
# =============================================================================
6+
7+
# -----------------------------------------------------------------------------
8+
# Stage 1: Build
9+
# -----------------------------------------------------------------------------
10+
FROM ghcr.io/arolang/aro-buildsystem:latest AS builder
11+
12+
WORKDIR /app
13+
14+
# Copy application source files
15+
COPY *.aro ./
16+
COPY openapi.yaml ./
17+
COPY templates/ ./templates/
18+
19+
# Compile to native binary
20+
RUN aro build . --optimize
21+
22+
# -----------------------------------------------------------------------------
23+
# Stage 2: Runtime
24+
# -----------------------------------------------------------------------------
25+
FROM ghcr.io/arolang/aro-runtime:latest
26+
27+
WORKDIR /app
28+
29+
# Copy compiled binary from builder
30+
COPY --from=builder /app/StatusPost ./StatusPost
31+
32+
# Copy runtime assets (templates, openapi spec)
33+
COPY --from=builder /app/openapi.yaml ./
34+
COPY --from=builder /app/templates/ ./templates/
35+
36+
# Expose HTTP port
37+
EXPOSE 8080
38+
39+
# Health check
40+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
41+
CMD curl -f http://localhost:8080/ || exit 1
42+
43+
# Run the application
44+
CMD ["./StatusPost"]

README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,64 @@ StatusPost/
4343
2. The page connects to `/ws` via WebSocket
4444
3. When a message is posted, it's stored and broadcast to all connected clients
4545
4. All clients receive the new message in real-time
46+
47+
## Docker
48+
49+
Build the container image:
50+
51+
```bash
52+
docker build -t statuspost:latest .
53+
```
54+
55+
Run locally:
56+
57+
```bash
58+
docker run -p 8080:8080 statuspost:latest
59+
```
60+
61+
## Kubernetes Deployment
62+
63+
Deploy to Kubernetes using kustomize:
64+
65+
```bash
66+
# Preview the manifests
67+
kubectl kustomize deployment/k8s/
68+
69+
# Apply to cluster
70+
kubectl apply -k deployment/k8s/
71+
```
72+
73+
Or apply manifests directly:
74+
75+
```bash
76+
kubectl apply -f deployment/k8s/deployment.yaml
77+
kubectl apply -f deployment/k8s/service.yaml
78+
kubectl apply -f deployment/k8s/ingress.yaml
79+
```
80+
81+
### Configuration
82+
83+
Edit `deployment/k8s/kustomization.yaml` to customize the image:
84+
85+
```yaml
86+
images:
87+
- name: statuspost
88+
newName: your-registry/statuspost
89+
newTag: v1.0.0
90+
```
91+
92+
Edit `deployment/k8s/ingress.yaml` to set your hostname:
93+
94+
```yaml
95+
spec:
96+
rules:
97+
- host: your-domain.com
98+
```
99+
100+
## CI/CD
101+
102+
GitHub Actions automatically builds and pushes the Docker image to `ghcr.io` on:
103+
104+
- Push to `main` branch → tagged as `main`
105+
- Version tags (`v*`) → tagged as version (e.g., `v1.0.0` → `1.0.0`)
106+
- Pull requests → build only (no push)

deployment/k8s/deployment.yaml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: statuspost
5+
labels:
6+
app: statuspost
7+
app.kubernetes.io/name: statuspost
8+
app.kubernetes.io/component: server
9+
spec:
10+
replicas: 1
11+
selector:
12+
matchLabels:
13+
app: statuspost
14+
template:
15+
metadata:
16+
labels:
17+
app: statuspost
18+
app.kubernetes.io/name: statuspost
19+
app.kubernetes.io/component: server
20+
spec:
21+
containers:
22+
- name: statuspost
23+
image: statuspost:latest
24+
imagePullPolicy: IfNotPresent
25+
ports:
26+
- name: http
27+
containerPort: 8080
28+
protocol: TCP
29+
livenessProbe:
30+
httpGet:
31+
path: /
32+
port: http
33+
initialDelaySeconds: 5
34+
periodSeconds: 10
35+
timeoutSeconds: 3
36+
failureThreshold: 3
37+
readinessProbe:
38+
httpGet:
39+
path: /
40+
port: http
41+
initialDelaySeconds: 3
42+
periodSeconds: 5
43+
timeoutSeconds: 2
44+
failureThreshold: 3
45+
resources:
46+
requests:
47+
memory: "64Mi"
48+
cpu: "50m"
49+
limits:
50+
memory: "256Mi"
51+
cpu: "500m"
52+
securityContext:
53+
readOnlyRootFilesystem: true
54+
runAsNonRoot: true
55+
runAsUser: 1000
56+
allowPrivilegeEscalation: false
57+
capabilities:
58+
drop:
59+
- ALL
60+
securityContext:
61+
seccompProfile:
62+
type: RuntimeDefault

deployment/k8s/ingress.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
apiVersion: networking.k8s.io/v1
2+
kind: Ingress
3+
metadata:
4+
name: statuspost
5+
labels:
6+
app: statuspost
7+
app.kubernetes.io/name: statuspost
8+
app.kubernetes.io/component: server
9+
annotations:
10+
# Enable WebSocket support
11+
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
12+
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
13+
nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr"
14+
# Optional: Enable SSL redirect
15+
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
16+
spec:
17+
ingressClassName: nginx
18+
rules:
19+
- host: statuspost.example.com
20+
http:
21+
paths:
22+
- path: /
23+
pathType: Prefix
24+
backend:
25+
service:
26+
name: statuspost
27+
port:
28+
name: http
29+
# Optional: TLS configuration
30+
# tls:
31+
# - hosts:
32+
# - statuspost.example.com
33+
# secretName: statuspost-tls

deployment/k8s/kustomization.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: kustomize.config.k8s.io/v1beta1
2+
kind: Kustomization
3+
4+
metadata:
5+
name: statuspost
6+
7+
resources:
8+
- deployment.yaml
9+
- service.yaml
10+
- ingress.yaml
11+
12+
commonLabels:
13+
app.kubernetes.io/part-of: statuspost
14+
app.kubernetes.io/managed-by: kustomize
15+
16+
images:
17+
- name: statuspost
18+
newName: ghcr.io/arolang/statuspost
19+
newTag: latest

deployment/k8s/service.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
name: statuspost
5+
labels:
6+
app: statuspost
7+
app.kubernetes.io/name: statuspost
8+
app.kubernetes.io/component: server
9+
spec:
10+
type: ClusterIP
11+
ports:
12+
- name: http
13+
port: 80
14+
targetPort: http
15+
protocol: TCP
16+
selector:
17+
app: statuspost

0 commit comments

Comments
 (0)