{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreihjky46flqmxpmdml7gdpj4rrqxd4bbredzwqczpqzgtkyfo5r5si",
    "uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3moysd5f2bf72"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreihmydjlsxqb6vzgltnt6tmhcnfragoy62ash2pibglyvmv42s52ei"
    },
    "mimeType": "image/webp",
    "size": 174732
  },
  "path": "/pavan_madduri/docker-init-ocir-oke-from-empty-folder-to-production-in-15-minutes-2o4e",
  "publishedAt": "2026-06-24T01:36:06.000Z",
  "site": "https://dev.to",
  "tags": [
    "docker",
    "oci",
    "devops",
    "platformengineering",
    "GitHub",
    "LinkedIn",
    "Website",
    "Google Scholar",
    "ResearchGate"
  ],
  "textContent": "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.\n\n##  What docker init Does\n\nIf 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.\n\n\n\n    mkdir oci-api && cd oci-api\n    go mod init github.com/pmady/oci-api\n\n    # Write a quick API\n    cat > main.go << 'EOF'\n    package main\n\n    import (\n        \"fmt\"\n        \"log\"\n        \"net/http\"\n        \"os\"\n    )\n\n    func main() {\n        http.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n            fmt.Fprintf(w, \"running on %s\", os.Getenv(\"OCI_REGION\"))\n        })\n        http.HandleFunc(\"/health\", func(w http.ResponseWriter, r *http.Request) {\n            w.WriteHeader(200)\n        })\n        log.Fatal(http.ListenAndServe(\":8080\", nil))\n    }\n    EOF\n\n\nNow the magic part:\n\n\n\n    $ docker init\n\n    Welcome to the Docker Init CLI!\n\n    ? What application platform does your project use? Go\n    ? What version of Go do you want to use? 1.22\n    ? What's the relative directory for your main package? .\n    ? What port does your server listen on? 8080\n\n\nIt generates three files:\n\n**Dockerfile** — Multi-stage build, distroless base, non-root user. Actually good defaults. I've seen teams write worse Dockerfiles by hand.\n\n**compose.yaml** — Basic setup with port mapping and env vars.\n\n**.dockerignore** — Excludes .git, binaries, vendor directory. Reasonable.\n\nThe generated Dockerfile looked like this (slightly simplified):\n\n\n\n    FROM golang:1.22 AS build\n    WORKDIR /src\n    COPY go.mod go.sum ./\n    RUN go mod download\n    COPY . .\n    RUN CGO_ENABLED=0 go build -o /bin/server .\n\n    FROM gcr.io/distroless/static-debian12:nonroot\n    COPY --from=build /bin/server /bin/\n    EXPOSE 8080\n    USER nonroot:nonroot\n    ENTRYPOINT [\"/bin/server\"]\n\n\nMulti-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.\n\n##  Minute 0-5: Build and Test Locally\n\n\n    docker compose up --build\n\n    # In another terminal\n    curl localhost:8080\n    # running on\n\n    curl localhost:8080/health\n    # 200 OK\n\n\nWorks. Five minutes in and I have a containerized API running locally.\n\n##  Minute 5-8: Push to OCIR\n\n\n    # Login\n    docker login iad.ocir.io -u '<tenancy-namespace>/pmady'\n\n    # Tag\n    docker tag oci-api-server:latest iad.ocir.io/<tenancy>/demos/oci-api:v1\n\n    # Quick scan\n    docker scout cves iad.ocir.io/<tenancy>/demos/oci-api:v1\n\n    # Push\n    docker push iad.ocir.io/<tenancy>/demos/oci-api:v1\n\n\nScout showed zero CVEs because distroless has almost nothing in it. Push took about 10 seconds because the image is 12MB.\n\n##  Minute 8-14: Deploy to OKE\n\nI already had an OKE cluster running (if you don't, add 20 minutes for `oci ce cluster create`). The deployment manifest:\n\n\n\n    # deploy.yaml\n    apiVersion: apps/v1\n    kind: Deployment\n    metadata:\n      name: oci-api\n    spec:\n      replicas: 2\n      selector:\n        matchLabels:\n          app: oci-api\n      template:\n        metadata:\n          labels:\n            app: oci-api\n        spec:\n          containers:\n            - name: api\n              image: iad.ocir.io/<tenancy>/demos/oci-api:v1\n              ports:\n                - containerPort: 8080\n              env:\n                - name: OCI_REGION\n                  value: us-ashburn-1\n              readinessProbe:\n                httpGet:\n                  path: /health\n                  port: 8080\n                periodSeconds: 5\n              resources:\n                requests:\n                  cpu: 100m\n                  memory: 64Mi\n                limits:\n                  cpu: 500m\n                  memory: 128Mi\n          imagePullSecrets:\n            - name: ocir-secret\n    ---\n    apiVersion: v1\n    kind: Service\n    metadata:\n      name: oci-api\n      annotations:\n        oci.oraclecloud.com/load-balancer-type: \"lb\"\n        service.beta.kubernetes.io/oci-load-balancer-shape: \"flexible\"\n        service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: \"10\"\n        service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: \"100\"\n    spec:\n      type: LoadBalancer\n      selector:\n        app: oci-api\n      ports:\n        - port: 80\n          targetPort: 8080\n\n\n\n    kubectl apply -f deploy.yaml\n\n    # Wait for LB IP\n    kubectl get svc oci-api -w\n    # NAME      TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)\n    # oci-api   LoadBalancer   10.96.1.120   129.153.xx.xx    80:31234/TCP\n\n    curl http://129.153.xx.xx/\n    # running on us-ashburn-1\n\n\n14 minutes. Empty folder to public API on OKE.\n\n##  What docker init Got Right\n\nI was skeptical about `docker init` being useful for anything beyond demos. But the generated Dockerfile was genuinely good:\n\n  * **Multi-stage build** — keeps the final image small\n  * **Distroless base** — minimal attack surface, near-zero CVEs\n  * **Non-root user** — security best practice out of the box\n  * **Separate dependency download** — `go mod download` before `COPY .` means dependencies are cached and rebuilds are fast\n\n\n\nThe 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).\n\n##  What It Doesn't Do\n\n`docker init` handles the Docker side. It doesn't generate:\n\n  * Kubernetes manifests\n  * CI/CD pipeline config\n  * OCIR login/push scripts\n  * Terraform for infrastructure\n\n\n\nThat'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.\n\n##  Languages I've Tested\n\nLanguage | Quality of Generated Dockerfile | Notes\n---|---|---\nGo | Excellent | Multi-stage, static binary, distroless\nPython | Good | Uses slim base, proper requirements.txt handling\nNode.js | Good | Multi-stage, npm ci for production\nRust | Excellent | cargo-chef for caching, musl for static binary\nJava | Decent | Uses Eclipse Temurin, could use jlink for smaller images\n\nGo 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.\n\n##  My Workflow Now\n\nFor quick services and prototypes, this is my default:\n\n\n\n    mkdir project && cd project\n    # write code\n    docker init\n    # tweak Dockerfile if needed\n    docker compose up --build      # test locally\n    docker push ...                # push to OCIR\n    kubectl apply -f deploy.yaml   # deploy to OKE\n\n\nThe gap between \"it works on my laptop\" and \"it's running on OKE\" is smaller than it's ever been.\n\n_Pavan Madduri — Oracle ACE Associate, CNCF Golden Kubestronaut. GitHub | LinkedIn | Website | Google Scholar | ResearchGate_",
  "title": "docker init OCIR OKE: From Empty Folder to Production in 15 Minutes"
}