External Publication
Visit Post

docker init OCIR OKE: From Empty Folder to Production in 15 Minutes

DEV Community [Unofficial] June 24, 2026
Source

I timed myself. Starting from an empty directory with a Go application idea, how fast could I get to a running deployment on OKE? The answer was 14 minutes. docker init did more of the work than I expected.

What docker init Does

If you haven't used it, docker init is an interactive scaffolding tool built into Docker CLI. You run it in your project directory and it generates a Dockerfile, .dockerignore, and docker-compose.yml tuned for your language.

mkdir oci-api && cd oci-api
go mod init github.com/pmady/oci-api

# Write a quick API
cat > main.go << 'EOF'
package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "running on %s", os.Getenv("OCI_REGION"))
    })
    http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(200)
    })
    log.Fatal(http.ListenAndServe(":8080", nil))
}
EOF

Now the magic part:

$ docker init

Welcome to the Docker Init CLI!

? What application platform does your project use? Go
? What version of Go do you want to use? 1.22
? What's the relative directory for your main package? .
? What port does your server listen on? 8080

It generates three files:

Dockerfile — Multi-stage build, distroless base, non-root user. Actually good defaults. I've seen teams write worse Dockerfiles by hand.

compose.yaml — Basic setup with port mapping and env vars.

.dockerignore — Excludes .git, binaries, vendor directory. Reasonable.

The generated Dockerfile looked like this (slightly simplified):

FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /bin/server .

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /bin/server /bin/
EXPOSE 8080
USER nonroot:nonroot
ENTRYPOINT ["/bin/server"]

Multi-stage, static binary, distroless, non-root. I'd write almost the same thing myself. The only change I made was adding -ldflags="-s -w" to strip debug symbols and shrink the binary.

Minute 0-5: Build and Test Locally

docker compose up --build

# In another terminal
curl localhost:8080
# running on

curl localhost:8080/health
# 200 OK

Works. Five minutes in and I have a containerized API running locally.

Minute 5-8: Push to OCIR

# Login
docker login iad.ocir.io -u '<tenancy-namespace>/pmady'

# Tag
docker tag oci-api-server:latest iad.ocir.io/<tenancy>/demos/oci-api:v1

# Quick scan
docker scout cves iad.ocir.io/<tenancy>/demos/oci-api:v1

# Push
docker push iad.ocir.io/<tenancy>/demos/oci-api:v1

Scout showed zero CVEs because distroless has almost nothing in it. Push took about 10 seconds because the image is 12MB.

Minute 8-14: Deploy to OKE

I already had an OKE cluster running (if you don't, add 20 minutes for oci ce cluster create). The deployment manifest:

# deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: oci-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: oci-api
  template:
    metadata:
      labels:
        app: oci-api
    spec:
      containers:
        - name: api
          image: iad.ocir.io/<tenancy>/demos/oci-api:v1
          ports:
            - containerPort: 8080
          env:
            - name: OCI_REGION
              value: us-ashburn-1
          readinessProbe:
            httpGet:
              path: /health
              port: 8080
            periodSeconds: 5
          resources:
            requests:
              cpu: 100m
              memory: 64Mi
            limits:
              cpu: 500m
              memory: 128Mi
      imagePullSecrets:
        - name: ocir-secret
---
apiVersion: v1
kind: Service
metadata:
  name: oci-api
  annotations:
    oci.oraclecloud.com/load-balancer-type: "lb"
    service.beta.kubernetes.io/oci-load-balancer-shape: "flexible"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "10"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "100"
spec:
  type: LoadBalancer
  selector:
    app: oci-api
  ports:
    - port: 80
      targetPort: 8080



kubectl apply -f deploy.yaml

# Wait for LB IP
kubectl get svc oci-api -w
# NAME      TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)
# oci-api   LoadBalancer   10.96.1.120   129.153.xx.xx    80:31234/TCP

curl http://129.153.xx.xx/
# running on us-ashburn-1

14 minutes. Empty folder to public API on OKE.

What docker init Got Right

I was skeptical about docker init being useful for anything beyond demos. But the generated Dockerfile was genuinely good:

  • Multi-stage build — keeps the final image small
  • Distroless base — minimal attack surface, near-zero CVEs
  • Non-root user — security best practice out of the box
  • Separate dependency downloadgo mod download before COPY . means dependencies are cached and rebuilds are fast

The only things I changed for OKE deployment were the -ldflags optimization and adding a health check endpoint (which docker init can't know about since it's application-specific).

What It Doesn't Do

docker init handles the Docker side. It doesn't generate:

  • Kubernetes manifests
  • CI/CD pipeline config
  • OCIR login/push scripts
  • Terraform for infrastructure

That's fair. It's a Docker tool, not a platform tool. But the Dockerfile it generates is solid enough that I don't need to edit it for most Go and Python projects.

Languages I've Tested

Language Quality of Generated Dockerfile Notes
Go Excellent Multi-stage, static binary, distroless
Python Good Uses slim base, proper requirements.txt handling
Node.js Good Multi-stage, npm ci for production
Rust Excellent cargo-chef for caching, musl for static binary
Java Decent Uses Eclipse Temurin, could use jlink for smaller images

Go and Rust output is good enough to use as-is. Python and Node need minor tweaks depending on your framework. Java needs the most work.

My Workflow Now

For quick services and prototypes, this is my default:

mkdir project && cd project
# write code
docker init
# tweak Dockerfile if needed
docker compose up --build      # test locally
docker push ...                # push to OCIR
kubectl apply -f deploy.yaml   # deploy to OKE

The gap between "it works on my laptop" and "it's running on OKE" is smaller than it's ever been.

Pavan Madduri — Oracle ACE Associate, CNCF Golden Kubestronaut. GitHub | LinkedIn | Website | Google Scholar | ResearchGate

Discussion in the ATmosphere

Loading comments...