You just wrote your first Python program — "Hello World!" It works on your laptop. Amazing!
But here's the scary part: What if you send that code to your friend, and it doesn't work on their computer? Different Python version. Missing libraries. Wrong operating system. Sound familiar?
Docker solves this exact problem. It packs your code, your Python version, and every library it needs into one neat, portable box called a Container Image — so it works the same everywhere. Every. Single. Time.
💡 Think of it like this: Imagine baking a cake and sealing it, the oven, the ingredients, AND the recipe all into one magic box. You hand the box to anyone in the world, and they can make an identical cake — no guesswork!
In this guide, we will go from a simple Python "Hello World" all the way to a live HTTPS endpoint running on Oracle Cloud (OCI) that anyone on the internet can call.
📋 What You Will Learn
- What Docker is and why it exists (with super simple analogies)
- Key Docker vocabulary: Image, Container, Dockerfile, Registry, Layer
- Write a real Python Flask API from scratch
- Write a Dockerfile and build your Container Image
- Test it locally on your own computer
- Push the image to OCI Container Registry (OCIR) — Oracle's private image library
- Deploy the image using OCI Container Instances — no server management!
- Expose it as a real HTTPS endpoint using OCI API Gateway
- End-to-end flow diagram: laptop → OCIR → Container Instance → HTTPS URL
- Best practices — DOs and DON'Ts every beginner must know
1. 🐳 What Exactly is Docker? (Plain English)
Docker is a tool that lets you package your application and everything it needs into a portable unit called a container.
A container is like a shipping container on a cargo ship. The shipping container doesn't care if the ship is going to Japan or Brazil. Inside, the cargo is always packed the same, perfectly protected. Docker containers work the same way — they run identically on your laptop, on Oracle's cloud, or on any server in the world.
Before Docker, developers had this constant headache: "It works on MY machine!" After Docker, everyone runs the exact same container. Problem solved forever. ✅
The Big Picture — How Docker Fits In
Your Python Code
+
Python 3.12 version
+ ──────► Docker Image ──────► Runs as a Container
All Libraries (Flask, etc.)
+
System settings
Everything is bundled into one Docker Image. That image can be stored, shared, and run anywhere.
2. 🧩 Key Docker Words You Must Know
Before writing any code, let's understand the 6 most important terms — explained simply:
🖼️ Docker Image
A Docker Image is the blueprint (the recipe card). It's a read-only snapshot of your app and everything it needs. You don't run the image directly — you create a Container from it.
🧒 Analogy: A cake recipe book. You can't eat the recipe — but you can bake a cake from it!
📦 Docker Container
A Container is a running instance of an Image. From one image, you can create 100 identical running containers — all independent of each other.
🧒 Analogy: The actual baked cake. You made it from the recipe. You can make 100 identical cakes from that one recipe!
📄 Dockerfile
A Dockerfile is a text file with instructions that tells Docker how to build your Image. Line by line, you describe: start from this base, install these packages, copy this code, run this command.
🧒 Analogy: The actual recipe written step by step. "Preheat oven to 180°C. Add 2 eggs. Mix for 5 minutes..."
🏪 Container Registry
A Container Registry is a storage and sharing hub for Docker Images. The most famous public one is Docker Hub. Oracle's private one (for OCI) is called OCIR — OCI Container Registry.
🧒 Analogy: A library where you can store and check out recipe books. OCIR is Oracle's private library — only you and your team can access it.
🧱 Image Layers
Every line in your Dockerfile creates a layer — a thin slice of the image. Docker is smart: if one layer hasn't changed, it reuses the cached version instead of rebuilding it. This makes builds much faster after the first time!
🧒 Analogy: A lasagne! Each sheet of pasta is a layer. If the bottom layers haven't changed, you only need to redo the top ones.
🔑 Auth Token
To push your image to OCIR (Oracle's private registry), you need an Auth Token — a special password that Oracle generates for you. You use this instead of your regular OCI password for Docker login.
3. 🛠️ What We Are Building — The End-to-End Flow
Here is exactly what we will build today, step by step:
┌──────────────────────────────────────────────────────────────────────┐ │ YOUR JOURNEY TODAY │ │ │ │ [1] Write Python Flask app (app.py + requirements.txt) │ │ ↓ │ │ [2] Write Dockerfile (the build recipe) │ │ ↓ │ │ [3] docker build → creates your Docker IMAGE on laptop │ │ ↓ │ │ [4] docker run → test it LOCALLY on your laptop │ │ ↓ │ │ [5] docker login OCIR → log in to Oracle's image library │ │ ↓ │ │ [6] docker push → upload image to OCIR (Oracle cloud storage) │ │ ↓ │ │ [7] OCI Container Instance → deploy image on Oracle's cloud │ │ ↓ │ │ [8] OCI API Gateway → expose as HTTPS endpoint (public URL!) │ │ ↓ │ │ [9] Anyone on internet calls: https://your-api.oracle.com/hello │ └──────────────────────────────────────────────────────────────────────┘
Let's build each part now! 🔨
4. 🐍 Step 1 — Write the Python Flask App
We will build a tiny Python web API using Flask. Flask is the simplest way to create a web server in Python — just a few lines and you have a working API!
Our API will have two endpoints:
/hello → returns a friendly greeting message,
and /health → returns a status check (used by cloud platforms to know the app is alive).
Create a project folder
These three terminal commands create a new folder on your laptop called
hello-docker-app
and move you inside it. Think of it as creating a new drawer to hold all your project files neatly.
# Create a new folder for our project mkdir hello-docker-app # Move into the folder cd hello-docker-app
Create app.py — the main Python application
This is our entire Python web application! It creates a tiny web server using Flask. When someone visits
/hello, the server replies with "Hello from OCI! 🚀".
When someone visits /health, it says "OK" — this is called a health check endpoint,
used by cloud services to confirm your app is running correctly.
The 0.0.0.0 means "listen for connections from anywhere" — this is important inside Docker!
# app.py — Our main Python web application
# This file creates a small web server with two URL endpoints
from flask import Flask, jsonify
import os
# Create the Flask application
app = Flask(__name__)
# ─────────────────────────────────────────────
# ENDPOINT 1: /hello
# When someone calls this URL, we return a JSON greeting
# ─────────────────────────────────────────────
@app.route('/hello', methods=['GET'])
def hello():
# Get a custom name from environment variable (optional)
# If not set, it defaults to "World"
name = os.environ.get("GREETING_NAME", "World")
return jsonify({
"message": f"Hello, {name}! 👋",
"status": "success",
"powered_by": "OCI Container Instance"
})
# ─────────────────────────────────────────────
# ENDPOINT 2: /health
# Cloud platforms call this to check if our app is alive
# It must return 200 OK for the platform to know we are healthy
# ─────────────────────────────────────────────
@app.route('/health', methods=['GET'])
def health():
return jsonify({"status": "healthy"}), 200
# ─────────────────────────────────────────────
# Start the web server
# host="0.0.0.0" means "accept connections from any network"
# → CRITICAL for Docker! Without this, the container can't receive requests.
# port=8080 is the port our server listens on
# ─────────────────────────────────────────────
if __name__ == '__main__':
port = int(os.environ.get("PORT", 8080))
app.run(host='0.0.0.0', port=port, debug=False)
Create requirements.txt — the list of Python libraries needed
This file is the shopping list for Python packages. When Docker builds our image, it reads this file and installs exactly these libraries.
flask is our web framework, gunicorn is a production-grade web server
(much better than Flask's built-in server for running in the cloud).
# requirements.txt — Python libraries our app needs # Docker will read this file and install all of these automatically flask==3.1.0 gunicorn==22.0.0
Flask's built-in web server (the one you see when you run
python app.py) is only for development.
It handles one request at a time and is not safe for production.
Gunicorn is a production-grade server that handles many requests simultaneously.
Always use Gunicorn (or uWSGI) in production Docker containers!
5. 📄 Step 2 — Write the Dockerfile
Now we write the Dockerfile — the recipe that tells Docker how to build our Image.
This file must be named exactly Dockerfile (capital D, no extension) and placed in the same folder as your app.
Think of this Dockerfile as a step-by-step cooking recipe for your application. Line 1: "Start with a Python 3.12 kitchen" (the base image). Line 2: "Create a special work area inside" (set working directory). Line 3: "Copy the shopping list and install ingredients" (install Python packages). Line 4: "Copy our actual code files in" (copy app.py). Line 5: "Open port 8080 so the outside world can reach us" (expose port). Line 6: "When the container starts, run the app using Gunicorn" (the startup command). Each line creates one layer in the final image.
# Dockerfile — The recipe for building our Docker Image # Every line here is a step in the build process # ── STEP 1: Choose the base image ────────────────────────────────────────── # We start from an official Python 3.12 image on a slim Linux system # "slim" means it has the minimum OS files needed — keeps our image small FROM python:3.12-slim # ── STEP 2: Set the working directory inside the container ───────────────── # All following commands will run from /app inside the container # Like saying "cd /app" but it also creates the folder if it doesn't exist WORKDIR /app # ── STEP 3: Copy requirements and install packages ───────────────────────── # We copy requirements.txt FIRST (before the code!) # Why? Because Docker caches layers — if requirements.txt hasn't changed, # Docker reuses the cached install layer → much faster rebuilds! COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # ── STEP 4: Copy our application code into the container ─────────────────── # The first "." means "everything in the current folder on my laptop" # The second "." means "copy it into /app inside the container" COPY . . # ── STEP 5: Tell Docker which port the app will listen on ────────────────── # This is documentation only — it doesn't actually open the port # You must also publish the port when running: docker run -p 8080:8080 EXPOSE 8080 # ── STEP 6: The command that runs when the container starts ──────────────── # We use Gunicorn (production server) instead of Flask's built-in server # "app:app" means: in the file "app.py", find the Flask object named "app" # --workers 2 means use 2 worker processes to handle requests # --bind 0.0.0.0:8080 means listen on all network interfaces on port 8080 CMD ["gunicorn", "--workers", "2", "--bind", "0.0.0.0:8080", "app:app"]
Your project folder should now look like this:
hello-docker-app/ ├── app.py ← Your Python Flask application ├── requirements.txt ← List of Python packages needed └── Dockerfile ← Recipe for building the Docker image
6. 🔨 Step 3 — Build the Docker Image
Now we run the docker build command. Docker reads your Dockerfile line by line and creates the image on your laptop.
docker build tells Docker to start building an image.
-t hello-oci-app:v1 gives the image a name (hello-oci-app) and a tag (v1 meaning version 1).
The final . (dot) means "look for the Dockerfile in the current folder."
Docker will run through your Dockerfile step by step — you'll see each layer being built in the terminal.
# Make sure you are inside the hello-docker-app folder # Then run this command to build the image docker build -t hello-oci-app:v1 .
You will see output like this (each layer prints its progress):
[+] Building 18.4s (9/9) FINISHED => [1/5] FROM python:3.12-slim 2.1s => [2/5] WORKDIR /app 0.1s => [3/5] COPY requirements.txt . 0.1s => [4/5] RUN pip install --no-cache-dir -r requirements 14.2s => [5/5] COPY . . 0.1s => exporting to image 1.4s => naming to docker.io/library/hello-oci-app:v1 0.1s Successfully built!
Check that the image was created by listing all your local images:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE hello-oci-app v1 a3b8c91d2f4e 2 minutes ago 145MB
Your image is ready! 🎉 Now let's test it before uploading to the cloud.
7. ▶️ Step 4 — Run and Test Locally
Before pushing to OCI, always test your container locally. This catches any bugs without wasting cloud resources.
docker run creates a running container from your image.
-d means run in the background (so you get your terminal back).
-p 8080:8080 is the magic part — it means "connect port 8080 on MY laptop to port 8080 INSIDE the container."
Without this, the container runs but is totally isolated — you can't reach it!
--name my-hello-app gives this running container a friendly name.
-e GREETING_NAME="OCI Learner" passes an environment variable into the container.
docker run -d \ -p 8080:8080 \ --name my-hello-app \ -e GREETING_NAME="OCI Learner" \ hello-oci-app:v1
Now test it by opening your browser to http://localhost:8080/hello — or use curl in terminal:
curl http://localhost:8080/hello
You should see:
{
"message": "Hello, OCI Learner! 👋",
"status": "success",
"powered_by": "OCI Container Instance"
}
Test the health endpoint too:
curl http://localhost:8080/health
{"status": "healthy"}
It works! 🎉 When you're done testing, stop and remove the local container:
# Stop the running container docker stop my-hello-app # Remove it from your local list docker rm my-hello-app
Fixing a bug locally takes 10 seconds. Fixing it after pushing to OCI takes 10 minutes. Never push an untested image — it will cost you time and frustration!
8. 🏪 Step 5 — Push Image to OCI Container Registry (OCIR)
Now we upload our image to OCIR — OCI Container Registry. Think of OCIR as Oracle's private image library, locked away safely in the cloud. Once the image is in OCIR, OCI Container Instances can pull it and run it for us.
What You Need First — Collect These 4 Values
Before running any commands, you need to find 4 pieces of information from your OCI account:
-
Your Region Key — the short code for your OCI region.
Find it in the OCI Console top bar. Examples:
us-ashburn-1,eu-frankfurt-1,ap-sydney-1. The OCIR URL format is:ocir.<region-identifier>.oci.oraclecloud.com -
Tenancy Namespace — a random string that identifies your OCI account.
Find it at: OCI Console → Profile (top right) → Tenancy → Object Storage Namespace.
Example:
ansh81vru1zp -
Your OCI Username — your email or username used to log into OCI.
Example:
john.doe@example.com - Auth Token — a special password for Docker login (NOT your regular OCI password). Create it at: OCI Console → Profile (top right) → My Profile → Auth Tokens → Generate Token. Copy it immediately — OCI will never show it again!
Docker login to OCIR uses an Auth Token as the password — not your OCI Console password. If you try your regular password, it will always fail with "unauthorized" error. Always generate and use an Auth Token!
Create a Repository in OCIR First
Before pushing, you need to create a repository (a named folder) in OCIR to hold your image.
- Go to OCI Console → Developer Services → Containers & Artifacts → Container Registry
- Click "Create repository"
- Enter name:
hello-oci-app - Access: choose Private (only your account can pull this image)
- Click Create
Tag Your Image for OCIR
Docker images need to know exactly WHERE to be pushed. The
docker tag command creates a new name for your existing image — a name that includes the full OCIR address.
It's like writing the destination address on a package before mailing it.
Format: ocir.<region>.oci.oraclecloud.com/<tenancy-namespace>/<repo-name>:<tag>
Replace the parts in angle brackets with your actual values!
# Replace these values with YOUR actual OCI details: # <region> = e.g., us-ashburn-1 # <tenancy-namespace> = e.g., ansh81vru1zp (found in Tenancy page) # <tag> = e.g., v1 docker tag hello-oci-app:v1 \ ocir.<region>.oci.oraclecloud.com/<tenancy-namespace>/hello-oci-app:v1 # Real example (replace with YOUR values): # docker tag hello-oci-app:v1 \ # ocir.us-ashburn-1.oci.oraclecloud.com/ansh81vru1zp/hello-oci-app:v1
Log In to OCIR
This logs Docker into OCI's container registry so it has permission to push images there. Your username must be in the format
<tenancy-namespace>/<your-email>.
Your password is the Auth Token you generated (NOT your OCI login password).
If you are a federated user (using Identity Cloud Service), use:
<tenancy-namespace>/oracleidentitycloudservice/<your-email>
docker login ocir.<region>.oci.oraclecloud.com \ --username '<tenancy-namespace>/<your-oci-email>' # Docker will then prompt you for password → paste your Auth Token here # Real example: # docker login ocir.us-ashburn-1.oci.oraclecloud.com \ # --username 'ansh81vru1zp/john.doe@example.com' # Password: (paste Auth Token here — it won't show as you type, that's normal!)
You should see: Login Succeeded ✅
Push the Image to OCIR
This uploads your Docker image from your laptop to Oracle's cloud registry. Docker pushes the image layer by layer — you'll see each layer's progress in the terminal. Once finished, your image lives safely in OCIR and can be deployed on any OCI service.
docker push ocir.<region>.oci.oraclecloud.com/<tenancy-namespace>/hello-oci-app:v1 # Real example: # docker push ocir.us-ashburn-1.oci.oraclecloud.com/ansh81vru1zp/hello-oci-app:v1
Terminal output:
The push refers to repository [ocir.us-ashburn-1.oci.oraclecloud.com/ansh81vru1zp/hello-oci-app] 8f3d2a1c4b9e: Pushed e7a19f3c8b4d: Pushed ... v1: digest: sha256:abc123... size: 3456 ✅ Image pushed successfully!
Go to OCI Console → Container Registry → find hello-oci-app → you'll see your image listed with tag v1. 🎉
9. 🚀 Step 6 — Deploy Using OCI Container Instances
OCI Container Instances is Oracle's serverless way to run containers. You don't need to set up a server, install an operating system, or manage any infrastructure. You just say "run THIS image" — Oracle handles everything else!
🧒 Analogy: Ordering food delivery vs. cooking yourself. Container Instances is the delivery service — you just say what you want, and it arrives ready to eat. No pots, no pans, no cleanup!
Create the Container Instance via OCI Console
Navigate to: OCI Console → Developer Services → Containers & Artifacts → Container Instances → Create Container Instance
Fill in the form:
-
Name:
hello-app-instance - Compartment: Select your compartment (the folder where your resources live)
-
Shape: Select
CI.Standard.E4.Flex. Then set OCPUs: 1 and Memory: 4 GB. (This is the size of the "virtual computer" that runs your container — 1 CPU core and 4 GB RAM is plenty for our Hello app!) - VCN and Subnet: Choose your VCN and a public subnet. A public subnet means the container instance gets a public IP address that the internet can reach. (If you don't have a VCN yet, create one via: Networking → Virtual Cloud Networks → Start VCN Wizard)
Under "Containers" section:
-
Image: Click "Select Image" → choose "OCI Container Registry" tab → select your image
hello-oci-app:v1 -
Port: Enter
8080(this is the port our Flask app listens on) -
Environment Variables: Click Add → Key:
GREETING_NAME, Value:OCI Cloud User
Click Create. Oracle now spins up a virtual machine, pulls your image from OCIR, and starts the container. This takes about 1–3 minutes.
Once the status shows ACTIVE, click on the Container Instance to see its Public IP address. Copy it!
Test the Container Instance Directly
This sends a test request to your running container on OCI. Replace
<public-ip> with the actual IP you copied from the Container Instance page.
If you get a response, your container is successfully running on Oracle's cloud! 🎉
# Test the running container on OCI
# Replace <public-ip> with your Container Instance's actual public IP
curl http://<public-ip>:8080/hello
# Expected response:
# {
# "message": "Hello, OCI Cloud User! 👋",
# "status": "success",
# "powered_by": "OCI Container Instance"
# }
OCI has a firewall called a Security List. By default it blocks all ports except 22 (SSH). To allow traffic on port 8080: OCI Console → Networking → Virtual Cloud Networks → your VCN → Security Lists → Default Security List → Add Ingress Rule → Source: 0.0.0.0/0, Port: 8080. After adding this rule, try curl again!
10. 🔒 Step 7 — Expose as HTTPS with OCI API Gateway
Our container is now running on OCI — but it's only reachable via plain HTTP on port 8080. A real production API needs a proper HTTPS URL with a valid SSL certificate. That's what OCI API Gateway gives us — a managed HTTPS front door for our app!
API Gateway also gives you: URL path routing, rate limiting, authentication, CORS handling — all without changing a single line of your app code!
🧒 Analogy: Your container is the kitchen. API Gateway is the fancy restaurant entrance with a glass door, a receptionist, and proper signage — it makes your kitchen accessible and presentable to the world!
Step A — Create the API Gateway
Navigate to: OCI Console → Developer Services → API Management → Gateways → Create Gateway
- Name:
hello-app-gateway - Type:
Public(so it's reachable from the internet) - Compartment: Your compartment
- VCN: Your VCN
- Subnet: Your public subnet
Click Create. Wait about 2 minutes for the gateway to become ACTIVE.
Once ACTIVE, click on the gateway to see its Hostname.
It will look like: abc123def456.apigateway.us-ashburn-1.oci.customer-oci.com
This is your HTTPS hostname. 🔒
Step B — Create an API Deployment
An API Deployment defines the routes — which URL paths forward to which backend. We'll create one deployment with two routes.
Inside your Gateway, click Deployments → Create Deployment:
- Name:
hello-app-deployment - Path Prefix:
/api
Now add Route 1:
- Path:
/hello - Methods: GET
- Backend Type: HTTP
- URL:
http://<your-container-instance-public-ip>:8080/hello
Click Add Route and add Route 2:
- Path:
/health - Methods: GET
- Backend Type: HTTP
- URL:
http://<your-container-instance-public-ip>:8080/health
Click Next → Create. Wait about 1–2 minutes for the deployment to become ACTIVE.
Step C — Test Your Live HTTPS Endpoint!
This is the moment of truth! We call our app through the API Gateway using a real HTTPS URL. The Gateway receives the request over secure HTTPS, forwards it to our container over HTTP on port 8080, and sends the response back to us — all automatically. Replace the hostname with the actual gateway hostname from your OCI Console.
# Your live HTTPS endpoint! Replace the hostname with your gateway's hostname.
curl https://abc123def456.apigateway.us-ashburn-1.oci.customer-oci.com/api/hello
# Expected response:
# {
# "message": "Hello, OCI Cloud User! 👋",
# "status": "success",
# "powered_by": "OCI Container Instance"
# }
You now have a real, publicly accessible HTTPS API endpoint running your Python code inside a Docker container on Oracle's cloud. 🎉🎉🎉
Share the URL with anyone in the world and they can call it! It uses a valid SSL certificate managed entirely by Oracle — zero SSL setup needed.
11. 🗺️ Complete Flow Diagram — Everything Together
YOUR LAPTOP
┌────────────────────┐
│ app.py │
│ requirements.txt │ docker build ──► Docker Image (hello-oci-app:v1)
│ Dockerfile │ │
└────────────────────┘ │ docker push
▼
┌──────────────────────────┐
│ OCIR (Container Registry)│
│ Oracle's Image Library │
│ ocir.region.oci.com/... │
└──────────────┬───────────┘
│ Pull image
▼
┌──────────────────────────┐
│ OCI Container Instance │
│ Running your container │
│ Public IP: xx.xx.xx.xx │
│ Port: 8080 │
└──────────────┬───────────┘
│ HTTP internally
▼
┌──────────────────────────┐
│ OCI API Gateway │
│ HTTPS (port 443) │
│ SSL managed by Oracle │
└──────────────┬───────────┘
│
▼
https://your-gateway.oci.com/api/hello
↑ Anyone on the internet can call this!
12. 🔄 Updating Your App — The Workflow
What happens when you fix a bug or add a new feature? Here is the simple update workflow — just 4 commands:
After changing your code, you rebuild the image with a new tag (
v2),
push the new version to OCIR, and then update the Container Instance to use the new image.
The API Gateway URL stays exactly the same — your users notice zero downtime!
# Step 1: Rebuild with a new version tag docker build -t hello-oci-app:v2 . # Step 2: Tag it for OCIR with the new version docker tag hello-oci-app:v2 \ ocir.<region>.oci.oraclecloud.com/<namespace>/hello-oci-app:v2 # Step 3: Push the new version to OCIR docker push ocir.<region>.oci.oraclecloud.com/<namespace>/hello-oci-app:v2 # Step 4: Update the Container Instance in OCI Console # Go to: Container Instances → your instance → Edit → change image tag from v1 to v2 # OCI will restart the container with the new image automatically
Using
:latest makes it hard to know what code is actually running.
Use version numbers like :v1, :v2, or date-based tags like :2026-04-18.
This way you can always roll back to a previous version if something breaks!
13. ✅❌ Best Practices — DOs and DON'Ts
Choose
python:3.12-slim instead of python:3.12.
The slim version strips out unnecessary tools and cuts image size by 60-70%.
Smaller images pull faster, start faster, and cost less to store!
Never do
ENV API_KEY=my-secret-key-here in a Dockerfile.
Any image is inspectable — anyone with the image can read all environment variables baked in.
Always pass secrets at runtime using environment variables or OCI Vault!
In your Dockerfile, always
COPY requirements.txt . and RUN pip install
BEFORE COPY . . (copying your code).
Docker caches each layer — if only your code changed (not requirements), Docker reuses
the cached install layer and rebuilds in seconds instead of minutes!
Never use
app.run(debug=True) or flask run in a production Docker container.
These are single-threaded and not safe. Always use Gunicorn or uWSGI
as the server inside your container — as we did with the CMD ["gunicorn", ...] line!
Just like
.gitignore excludes files from Git, .dockerignore excludes files from being copied into your image.
This keeps your image lean and prevents accidentally including local secrets.
This is a sample
.dockerignore file. Create it in the same folder as your Dockerfile.
It tells Docker to skip these files when doing COPY . . — keeping your image clean and small.
# .dockerignore — files and folders to EXCLUDE from the Docker image # Create this file in the same folder as your Dockerfile __pycache__/ # Python bytecode cache — not needed in the image *.pyc # Compiled Python files — not needed *.pyo # Optimised Python files — not needed .env # Local environment file — may contain secrets! .git/ # Git history — not needed inside the container .gitignore # Git config — not needed inside the container *.md # Documentation files — not needed at runtime tests/ # Test files — not needed in production image
By default, Docker runs your app as the
root user inside the container.
This is a security risk — if someone compromises your app, they'd have root access.
Add USER 1000 (a non-root user) near the end of your Dockerfile as a security best practice!
Every containerised app should expose a
/health endpoint that returns HTTP 200 OK.
OCI Container Instances and Kubernetes use this to check if your app is alive.
If it stops responding to health checks, the platform automatically restarts your container!
14. 📝 Quick Reference — Essential Docker Commands
docker build -t <name>:<tag> .→ Build an image from a Dockerfile in the current folderdocker images→ List all images on your laptopdocker run -d -p 8080:8080 --name <name> <image>→ Run a container in the backgrounddocker ps→ List all currently running containersdocker ps -a→ List ALL containers (running + stopped)docker logs <container-name>→ See the output/logs of a running containerdocker exec -it <container-name> bash→ Open a terminal shell inside a running containerdocker stop <container-name>→ Gracefully stop a running containerdocker rm <container-name>→ Delete a stopped containerdocker rmi <image-name>→ Delete an image from your laptopdocker tag <local-image> <ocir-path>→ Tag an image for OCIRdocker login <ocir-url> --username <namespace/email>→ Log in to OCIRdocker push <ocir-path>→ Push an image to OCIRdocker pull <image-path>→ Download an image from a registry
Summary 📝
What we built — Complete Docker → OCI → HTTPS journey:
- Docker Image → A portable, self-contained bundle of your app + dependencies
- Dockerfile → The recipe that tells Docker how to build the image, layer by layer
- docker build → Turns your Dockerfile into a runnable image on your laptop
- docker run → Creates a running container from the image, locally for testing
- OCIR → Oracle's private container image storage — your cloud image library
- Auth Token → The special password used for Docker login to OCIR (not your OCI password!)
- docker tag + push → Labels and uploads the image to OCIR
- OCI Container Instances → Serverless way to run containers on Oracle's cloud — no server setup!
- OCI API Gateway → Puts a proper HTTPS front door on your container, with SSL handled automatically
- Update workflow → Build v2 → Push v2 → Update Container Instance → zero downtime!
Happy containerising! 🐳☁️✨
Comments
Post a Comment