# Resource + How to test Dockerfiles? https://medium.com/@michamarszaek/how-to-test-dockerfiles-9a208dded84b + Checking your build configuration https://docs.docker.com/build/checks/ --- --- # Confusing Concepts for Dockerfile ## **Why Use `COPY`?** The `COPY` command copies files/folders from **your local machine** (host) into the **image** you’re building. ### Example: ```dockerfile COPY ./my-app /var/www/html ``` This is like packing ingredients (your source code) into the meal box (image). Without `COPY`, your container would have no access to your app files. --- ## `CMD` & `ENTRYPOINT`? In Docker, both `CMD` and `ENTRYPOINT` define the **default behavior** of a container when it runs. However, they serve **different purposes** and are used **in different scenarios**. Understanding when to use one or both depends on the level of control and flexibility you want in your container's behavior. ### πŸ”Ή CMD β€” Default Arguments * **Purpose**: Provides **default arguments** to the container's main command. * **Overridable**: Yes β€” arguments passed at runtime (e.g., `docker run myimage [args]`) will **override CMD**. * **Use case**: When you want to give users the ability to **easily override the behavior** without modifying the Dockerfile. ```Dockerfile # Example CMD ["nginx", "-g", "daemon off;"] ``` ### πŸ”Ή ENTRYPOINT β€” Fixed Executable * **Purpose**: Defines the **main command** to run inside the container. * **Overridable**: No β€” runtime arguments are **passed to ENTRYPOINT** as arguments, not replacements. * **Use case**: When you want to ensure a **specific command always runs**, and only the arguments might change. ```Dockerfile # Example ENTRYPOINT ["nginx"] ``` ### πŸ”Έ Using Both Together You can combine them to make a **stable command structure with flexible arguments**: ```Dockerfile ENTRYPOINT ["nginx"] CMD ["-g", "daemon off;"] ``` * Result: `docker run myimage` runs `nginx -g daemon off;` * You can override the CMD part like this: ```bash docker run myimage -g "daemon on;" ``` ### βœ… When to Use Each: #### βœ… Use **`CMD`** when: * You want to provide **default arguments** for a command. * You want users to **override the command entirely** at runtime using `docker run <image> <new_command>`. * You are building **base images** that others will extend and customize. πŸ“Œ **Example use case**: A Python base image ```Dockerfile FROM python:3.12 CMD ["python3"] ``` β†’ Users can run: `docker run myimage script.py` #### βœ… Use **`ENTRYPOINT`** when: * You want the **command to always run**, regardless of what the user provides at runtime. * You want the container to behave like a **binary** or **command wrapper**. * You're building a final application image where **execution behavior should not be changed**. πŸ“Œ **Example use case**: A container that always runs a shell script ```Dockerfile FROM alpine ENTRYPOINT ["/entrypoint.sh"] ``` β†’ `docker run myimage arg1 arg2` will run `/entrypoint.sh arg1 arg2` #### βœ… Use **`ENTRYPOINT` + `CMD`** together when: * You want to **enforce a specific command** (via `ENTRYPOINT`) but allow **default or overridable arguments** (via `CMD`). * This is the **most common setup** for production containers. πŸ“Œ **Example use case**: A web server with configurable flagsFixed command + flexible arguments ENTRYPOINT + CMD ```Dockerfile FROM nginx ENTRYPOINT ["nginx"] CMD ["-g", "daemon off;"] ``` β†’ `docker run myimage` runs `nginx -g daemon off;` β†’ `docker run myimage -g 'daemon on;'` overrides the CMD part only. #### ❌ Avoid: * Using both in shell form (`ENTRYPOINT nginx` and `CMD -g 'daemon off;'`) β€” this can lead to unpredictable behavior and broken signal handling. --- ## 🧠 Summary | `CMD` vs `ENTRYPOINT` * Use **`CMD`** when you want **default, overridable parameters**. * Use **`ENTRYPOINT`** when you want to **enforce the command being run**. * **Use both together** when you want fixed commands with flexible default arguments. | Situation | Use | | ------------------------------------------------------------- | -------------------- | | Building a base image for general use | `CMD` | | Building a container with one fixed job | `ENTRYPOINT` | | Fixed command + flexible arguments | `ENTRYPOINT` + `CMD` | | You want `docker run <image>` to feel like running a CLI tool | `ENTRYPOINT` | | Scenario | Use `CMD` | Use `ENTRYPOINT` | | -------------------------------------------------------- | --------- | ---------------------- | | Want to allow user to override full command easily | βœ… | ❌ | | Want to always run a specific program (e.g., app binary) | ❌ | βœ… | | Want to provide default Fixed command + flexible arguments ENTRYPOINT + CMD parameters but allow overrides | βœ… | βœ… (combined use) | | Writing a base image meant to be extended | βœ… | Usually not | | Writing a final application container | Maybe | βœ… (for predictability) | --- --- # TEST Dockerfile ## βœ… STEP 1 β€” Build the Docker Image Open terminal and navigate to the folder where your Dockerfile is: ```bash cd path/to/your/nginx-folder ``` Then run: ```bash docker build -t my_nginx_image . ``` * `-t my_nginx_image` gives your image a name. * `.` means build from the current directory. βœ… **Success looks like**: β€œ`Successfully tagged my_nginx_image:latest`” --- ## βœ… STEP 2 β€” Run the Container Because port `443` is privileged (<1024), beginners often get permission errors. So map container’ Docker image docker build -t my-nginx-image .s port `443` to a higher host port, like `8443`: ```bash docker run -d --rm -p 8443:443 --name my_nginx_container my_nginx_image ``` Fixed command + flexible arguments ENTRYPOINT + CMD * `-d` = detached (background mode) * `--rm` = auto remove container on stop * `-p 8443:443` = map host port 8443 β†’ container port 443 * `--name my_nginx_container` = name your container * `my_nginx_image` = name of the image you built --- ## βœ… STEP 3 β€” Test the Container ### βœ… Option A: Use `curl` Run this: ```bash curl -k https://localhost:8443 ``` * `-k` = skip SSL cert validation (because it's self-signed) If Nginx is running correctly, you should see HTML content or a response (even if empty). If not, you’ll get an error. ---Fixed command + flexible arguments ENTRYPOINT + CMD ### βœ… Option B: Use Browser Open your browser and go to: ``` https://localhost:8443 ``` You’ll probably see a **"Your connection is not private" warning** β€” that’s expected due to the sel Docker image docker build -t my-nginx-image .f-signed certificate. Click **β€œProceed anyway”** to view the site. --- ## βœ… STEP 4 β€” Check Container Logs (Optional) If you need to debug: ```bash docker logs my_nginx_contaFixed command + flexible arguments ENTRYPOINT + CMD iner ``` To stop the container: ```bash docker stop my_nginx_container ``` --- ## βœ… SUMMARY | Step | Command | | ----------------- | ------------------------------------------------------------------------- | | πŸ”§ Build image | `docker build -t my_nginx_image .` | | β–Ά Run container | `docker run -d --rm -p 8443:443 --name my_nginx_container my_nginx_image` | | πŸ” Test with curl | `curl -k https://localhost:8443` | | πŸ§ͺ View logs | `docker logs my_nginx_container` | | β›” Stop container | `docker stop my_nginx_container` | --- # Essentia Docker image docker build -t my-nginx-image .l Docker commands ## 🧱 1. **Building Docker Images** ### πŸ”¨ Build a Docker image ```bash docker build -t my-nginx-image ./nginx docker build -t my-wordpress-image ./wordpress docker build -t my-mariadb-image ./mariadb ``` * `-t` gives the image a name * `./folder` points to where the Dockerfile is --- ## ▢️ 2. **Running Docker Containers** ### πŸ” Run a container from an image ```bash docker run -d --name nginx-server -p 8080:80 my-nginx-image docker run -d --name wordpress-app -p 9000:9000 my-wordpress-image docker run -d --name mariadb-server -e MYSQL_ROOT_PASSWORD=rootpass -e MYSQL_DATABASE=wordpress my-mariadb-image ``` > `-e` sets environment variables like passwords and database names. --- ## πŸ—‚οΈ 3. **Volumes (Persistent Storage)** ### πŸ“¦ Create and use named volumes ```bash docker volume create wordpress-data docker volume create db-data ``` ### πŸ” Attach volume to container ```bash docker run -d \ --name wordpress-app \ -v wordpress-data:/var/www/html \ my-wordpress-image ``` ```bash docker run -d \ --name mariadb-server \ -v db-data:/var/lib/mysql \ my-mariadb-image ``` --- ## πŸ” 4. **Monitoring & Debugging** ### πŸ”Ž See all running containers ```bash docker ps ``` ### πŸ“œ See logs of a container ```bash docker logs wordpress-app ``` ### 🧼 Enter the shell inside a running container ```bash docker exec -it wordpress-app bash ``` --- ## ❌ 5. **Stopping and Removing** ### πŸ›‘ Stop a running container ```bash docker stop wordpress-app ``` ### πŸ—‘οΈ Remove a container ```bash docker rm wordpress-app ``` ### ❎ Remove an image ```bash docker rmi my-wordpress-image ``` --- ## πŸ”„ 6. **Using Docker Compose** (recommended for multi-container setups) ### ▢️ Start services from `docker-compose.yml` ```bash docker-compose up -d ``` ### πŸ”„ Restart ```bash docker-compose restart ``` ### πŸ›‘ Stop all services ```bash docker-compose down ``` --- ## 🧠 Summary Sheet | Task | Command Example | | ------------------------- | -------------------------------------------- | | Build an image | `docker build -t my-image .` | | Run a container | `docker run -d --name my-container my-image` | | Create a volume | `docker volume create my-volume` | | View logs | `docker logs my-container` | | Enter shell | `docker exec -it my-container bash` | | Stop a container | `docker stop my-container` | | Delete a container/image | `docker rm` / `docker rmi` | | Run multi-container stack | `docker-compose up -d` |