Reading view

There are new articles available, click to refresh the page.

Docker Ep 9: The Building Blocks – Detailed Structure of a Dockerfile

Alex now knows the basics, but it’s time to get their hands dirty by writing an actual Dockerfile.

The FROM Instruction: Choosing the Foundation

The first thing Alex learns is the FROM instruction, which sets the base image for their container. It’s like choosing the foundation for a house.

  • Purpose:
    • The FROM instruction initializes a new build stage and sets the Base Image for subsequent instructions.
  • Choosing a Base Image:
    • Alex decides to use a Python base image for their application. They learn that python:3.9-slim is a lightweight version, saving space and reducing the size of the final image.

FROM python:3.9-slim

Example: Think of FROM as picking the type of bread for your sandwich. Do you want white, whole wheat, or maybe something gluten-free? Your choice sets the tone for the rest of the recipe.

The LABEL Instruction: Adding Metadata (Optional)

Next, Alex discovers the LABEL instruction. While optional, it’s a good practice to include metadata about the image.

  • Purpose:
    • The LABEL instruction adds metadata like version, description, or maintainer information to the image.
  • Example:
    • Alex decides to add a maintainer label:

LABEL maintainer="alex@example.com"

Story Note: This is like writing your name on a sandwich wrapper, so everyone knows who made it and what’s inside.

The RUN Instruction: Building the Layers

The RUN instruction is where Alex can execute commands inside the image, such as installing dependencies.

  • Purpose:
    • The RUN instruction runs any commands in a new layer on top of the current image and commits the results.
  • Example:
    • To install the Flask framework, Alex writes:

RUN pip install flask

They also learn to combine commands to reduce layers:


RUN apt-get update && apt-get install -y curl

Story Note: Imagine slicing tomatoes and cheese for your sandwich and placing them carefully on top. Each ingredient (command) adds a layer of flavor.

The COPY and ADD Instructions: Bringing in Ingredients

Now, Alex needs to bring their application code into the container, which is where the COPY and ADD instructions come into play.

  • COPY:
    • The COPY instruction copies files or directories from the host filesystem into the container’s filesystem.
  • ADD:
    • The ADD instruction is similar to COPY but with additional features, like extracting compressed files.
  • Example:
    • Alex copies their application code into the container:

COPY . /app

Story Note: This is like moving ingredients from your fridge (host) to the counter (container) where you’re preparing the sandwich.

The WORKDIR Instruction: Setting the Workspace

Alex learns that setting a working directory makes it easier to manage paths within the container.

  • Purpose:
    • The WORKDIR instruction sets the working directory for subsequent instructions.
  • Example:
    • Alex sets the working directory to /app:

WORKDIR /app

Story Note: This is like setting up a designated area on your counter where you’ll assemble your sandwich—keeping everything organized.

The CMD and ENTRYPOINT Instructions: The Final Touch

Finally, Alex learns how to define the default command that will run when the container starts.

  • CMD:
    • Provides defaults for an executing container, but can be overridden.
  • ENTRYPOINT:
    • Configures a container that will run as an executable, making it difficult to override.
  • Example:
    • Alex uses CMD to specify the command to start their Flask app:

CMD ["python", "app.py"]

Story Note: Think of CMD as the final step in making your sandwich—like deciding to add a toothpick to hold everything together before serving.

Below is an example Dockerfile of a flask application,


# Use an official Python runtime as a parent image
FROM python:3.9-slim

# Set the working directory in the container
WORKDIR /app

# Copy the current directory contents into the container at /app
COPY . /app

# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

Breakdown of the Dockerfile:

  1. FROM python:3.9-slim:
    • This line specifies the base image. In this case, it uses a slim version of Python 3.9, which is lightweight and sufficient for a simple Flask application.
  2. WORKDIR /app:
    • This sets the working directory inside the container to /app. All subsequent commands will be run inside this directory.
  3. COPY . /app:
    • This copies everything from your current directory on the host machine into the /app directory inside the container.
  4. RUN pip install –no-cache-dir -r requirements.txt:
    • This installs the necessary Python packages listed in the requirements.txt file. The --no-cache-dir option reduces the image size by not caching the downloaded packages.
  5. EXPOSE 80:
    • This makes port 80 available for external access. It’s where the Flask application will listen for incoming requests.
  6. ENV NAME World:
    • This sets an environment variable NAME to “World”. You can access this variable in your Python code.
  7. CMD [“python”, “app.py”]:
    • This tells the container to run the app.py file using Python when it starts.

Example Flask Application (app.py):

To complete the example, here’s a simple Flask application you can use:


from flask import Flask
import os

app = Flask(__name__)

@app.route('/')
def hello():
    name = os.getenv('NAME', 'World')
    return f'Hello, {name}!'

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)

Example requirements.txt:

And here’s the requirements.txt file listing the dependencies for the Flask app:


Flask==2.0.3

Building and Running the Docker Image:

  1. Build the Docker image using the Dockerfile:
docker build -t my-flask-app .

2. Run the Docker container:


docker run -p 4000:80 my-flask-app
  • This maps port 4000 on your host machine to port 80 in the container.

Open your browser and go to http://localhost:4000, and you should see “Hello, World!” displayed on the page.

You can customize the ENV NAME in the Dockerfile or by passing it as an argument when running the container:


docker run -p 4000:80 -e NAME=Alex my-flask-app

This will display “Hello, Alex!” instead.

Docker Ep 8: Tomcat: Exploring Docker Port Mapping and Logs

Caution: We are just starting from basics. Even if you don’t understand below concepts there is no problem.

In our previous adventures, we’ve dabbled in Docker’s mysterious arts, running containers, inspecting them, and even detaching them to roam in the background.

Today, we’re stepping up our game by diving into Docker port mapping and the powerful docker logs command. And what better companion for this journey than the Tomcat image, a trusty open-source web server that brings Java servlets to life?

Summoning the Tomcat Image

To begin, we need to summon our new ally: the Tomcat image. Tomcat is a legendary web server that, by default, operates on port 8080 within its container. But what if we want to make this web server accessible to the outside world through a different port? This is where Docker’s port mapping comes into play.

First, let’s visit the Docker Hub and search for the Tomcat image. Once there, we can see that Tomcat will run on port 8080 by default. We’ll need to expose this port and map it to a port on our host machine using the -p option.

Port Mapping: Connecting the Container to the World

Docker port mapping allows us to make the services inside our container accessible from the outside world by forwarding a host port to a container port. The syntax for port mapping is:

-p <host_port>:<container_port>

For example, let’s say we want to map port 8080 inside the container to port 8888 on our host machine. This means that when we access port 8888 on our host, we’ll actually be talking to port 8080 inside the Tomcat container.

Let’s see this in action.

Running Tomcat with Port Mapping

Fire up your Docker terminal, make sure the font size is nice and large, and enter the following command:

docker run -it -p 8888:8080 tomcat:8.0

Here’s what’s happening:

  • -it runs the container interactively.
  • -p 8888:8080 maps port 8080 inside the container to port 8888 on our host.
  • tomcat:8.0 specifies the Tomcat image and its version.

Now, sit back and relax (or maybe grab a coffee) as Docker pulls down the Tomcat image. It’s about 300 MB, so depending on your internet connection, this might take a moment.

Once the image is downloaded, Docker will spin up the container, and our Tomcat server will be ready to roll.

Accessing the Tomcat Server

With the Tomcat container up and running, we can access the Tomcat web server through our web browser. But first, we need to know where to find it.

If you’re running Docker on Linux, or using Docker for Mac or Windows, the host IP is simply localhost. If you’re using Docker Machine, you’ll need to grab the IP address of the Docker Machine.

Now, open up your browser, type in localhost:8888 (or your Docker Machine’s IP address followed by :8888), and hit Enter.

The Tomcat console page should greet you warmly.

Running Tomcat in Detached Mode

While running a container in the foreground is great for testing, in production, we typically want our containers to run in the background. For this, we use the -d flag to run the container in detached mode.

Let’s modify our previous command to run Tomcat in the background:

docker run -d -p 8888:8080 tomcat:8.0

After hitting Enter, Docker will return a long container ID, confirming that Tomcat is now running in the background, silently serving up Java servlets.

Checking Container Status with docker ps -a

Curious about the status of your Tomcat container? Use the docker ps -a command to list all the containers on your system, including those that have exited. This is a handy way to check if your container is still running or if it has quietly exited.

docker ps -a

Reading the Tea Leaves: docker logs

Sometimes, you want to peek into the inner workings of your running containers to see what they’re up to. This is where the docker logs command comes in. It lets you view the logs generated by your container, which can be incredibly useful for debugging or just keeping an eye on things.

Let’s say you want to check the logs of your running Tomcat container. You would run:

docker logs <container_id>

There is more on docker logs, we shall see later.

❌