Ship your first app (Dockerfile)
This builds an app from a Dockerfile, pushes it to your registry, and serves it over HTTPS. The Dockerfile approach works for any language; this example uses a small Go server to mirror the ko guide. If your app is in Go, ko is the shorter path.
It assumes:
- You can reach your cluster with
kubectl(see the kubectl quickstart). - You’ve set up GHCR credentials: a local push login and the
ghcrpull secret in thedemonamespace (see Set up GHCR credentials). - The optional ingress bundle is installed, for HTTPS (see Expose a service with Ingress).
- You have Docker installed locally. No language toolchain is needed: the build runs inside the image.
Write the app
Section titled “Write the app”mkdir hello && cd hellocat <<'EOF' > go.modmodule example.com/hello
go 1.23EOFcat <<'EOF' > main.gopackage main
import ( "fmt" "log" "net/http")
func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "hello from skube - dockerfile") }) log.Fatal(http.ListenAndServe(":8080", nil))}EOFA multi-stage Dockerfile compiles the binary, then copies it onto a tiny base image:
cat <<'EOF' > DockerfileFROM golang:1.23 AS buildWORKDIR /srcCOPY . .RUN CGO_ENABLED=0 go build -o /hello .
FROM gcr.io/distroless/staticCOPY --from=build /hello /helloENTRYPOINT ["/hello"]EOFBuild and push
Section titled “Build and push”docker build -t ghcr.io/<github-username>/hello:v1 .docker push ghcr.io/<github-username>/hello:v1Write the manifest
Section titled “Write the manifest”cat <<'EOF' | kubectl apply -f -apiVersion: apps/v1kind: Deploymentmetadata: name: hello namespace: demospec: replicas: 1 selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - name: hello image: ghcr.io/<github-username>/hello:v1 ports: - containerPort: 8080---apiVersion: v1kind: Servicemetadata: name: hello namespace: demospec: selector: app: hello ports: - port: 80 targetPort: 8080---apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: hello namespace: demo annotations: cert-manager.io/cluster-issuer: letsencrypt-prodspec: ingressClassName: traefik tls: - hosts: - hello.example.com secretName: hello-tls rules: - host: hello.example.com http: paths: - path: / pathType: Prefix backend: service: name: hello port: number: 80EOFThe pushed package is private by default, which is why the cluster needs the
ghcr pull secret from the credentials guide.
Verify
Section titled “Verify”kubectl get certificate hello-tls -n demo -wOnce READY is True:
curl https://hello.example.comYou should get back hello from skube - dockerfile.
Clean up
Section titled “Clean up”kubectl delete namespace demo