Understanding The Basic Syntax Of A Dockerfile.
Tags: docker, container, python
Published: 2024-03-12 21:23:07

This article will help you understand the basic commands for creating a Dockerfile which you will use when containerizing different applications and also highlight the benefits of a Dockerfile. Whether you are new to Docker or not, this article will provide valuable information and tips when working with a Dockerfile with different programming languages like Python, Go, Node.Js, Rust, PHP, e.t.c. You will also see how to use the docker init command which initializes the creation of Dockerfiles, compose.yaml and other resources that simplifies the process of configuring Docker.
### What is a Dockerfile?
A Dockerfile is a script file that contains instructions or commands for building a docker image. The Dockerfile provides instructions to the Docker engine on how to assemble an image. It includes instructions for installing dependencies, copying files, setting environment variables, and configuring the container. It uses a simple, easy-to-read syntax that can be created and edited with any text editor. Once a Dockerfile has been created, it can be used to build an image using the docker build command. The resulting image can then be run as a container using docker run command.
### Why is a Dockerfile necessary?
Dockerfiles enable faster, more efficient, consistent deployment processes for applications. It is necessary and beneficial for several reasons when working with Docker and containerized applications such as:
Reproducibility: Dockerfiles provide a clear and reproducible set of instructions for building a Docker image. This helps ensure consistency across different environments, making it easier to share and deploy applications with the confidence that they will behave the same way everywhere.

Version Control: Dockerfiles can be version-controlled along with the source code of an application. This allows teams to track changes to the build process and easily roll back to previous versions if needed. It enhances collaboration and provides a history of how the application's environment has evolved.

Dependency Management: Dockerfiles explicitly list the dependencies and configuration needed for an application to run. This includes base images, system libraries, runtime environments, and any other software dependencies. This makes it easy to understand and manage the software stack of an application.

Efficient Builds: Docker images are built in layers, and Dockerfile instructions contribute to these layers. When a change is made in the codebase or dependencies, only the affected layers need to be rebuilt, making the build process more efficient and faster.

Isolation: Dockerfiles encapsulate the configuration of an application, making it isolated from the underlying host system. This isolation helps avoid conflicts with other applications or dependencies on the host and ensures that the application runs consistently, regardless of the host environment.

Automation: Dockerfiles allow for the automation of the containerization process. Continuous Integration (CI) and Continuous Deployment (CD) pipelines can use Dockerfiles to build and deploy applications automatically. This automation streamlines the development and deployment workflows, reducing the chance of manual errors.

Portability: Dockerfiles contribute to the portability of applications. Since they define the entire environment needed for an application, Docker images created from these Dockerfiles can run consistently on any system that supports Docker. This portability simplifies deployment across different environments, from development to production.

### How to create a Dockerfile?
The fundamental Dockerfile command remains consistent but the content and structure varies across different programming languages and technology stack. The basic structure of a Dockerfile is based on a set of simple instructions, such as "FROM", "WORKDIR", "RUN", "COPY", "EXPOSE", "ENV". Each instruction adds a new layer to the image and each layer includes the instructions specified in the previous layer. The final image is a result of all the instructions specified in the Dockerfile.
> Note: Create a file called Dockerfile, use any text editor of your choice.

FROM: A dockerfile always starts by importing the base image using this keyword.

```
From <image>
```

WORKDIR: this sets the working directory. This means that any instructions that are run in the container will be executed inside the specified directory.
```
WORKDIR <directory>
```

COPY: the COPY instruction is used to copy files or directories from the host machine into the container current working directory.
```
COPY <src> <dst>
```

If you want to copy all the files from the host current directory to the container's current directory use:
```
COPY . .
```

The first "." represents the source directory on the host machine and the second "." represents the destination directory within the container.

RUN: use the run command to execute commands during the image build process. It is used to install necessary packages, run build scripts, e.t.c.
```
RUN <command>
```
CMD: this specifies the specific command to run when a container is started.
```
CMD ["executable","param1","param2",…]
```
ENV: this instruction sets environment variables inside the container which will be available during build time as well as in a running container(image).
```
ENV MY_VAR=my_value.
```

EXPOSE: this command informs docker that the port the container listens to during run time. It is more of a documentation, it doesn't publish the port.
```
EXPOSE 5000
```

Apart from the commands listed above, there are many others like ENTRYPOINT, ARG, VOLUME, USER, LABEL, e.t.c which are also used to create a Dockerfile but we focused on the basics.

Sample of a Dockerfile for a Flask App:
```
FROM python:3.12-slim

EXPOSE 5000

# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE=1

# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED=1

# Install pip requirements
COPY requirements.txt .
RUN python -m pip install -r requirements.txt 

WORKDIR /app
COPY . /app

CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
```
### What is Docker Init?
Docker init is a CLI command that helps you initialize Docker resources in your projects. It walks you through the creation of Dockerfiles, compose.yaml, .dockerignore files and so on based on your project's requirements. This helps to save time and reduce complexity when configuring Docker for your projects.
### How to use Docker init?
Using Docker init is easy, after installing it, go to the directory of your project where you want to set up Docker.
Create a basic flask app:
```
from flask import Flask

app = Flask(__name__)

@app.route('/')
def docker():
     return "Dockerfile Tutorial"

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)
```
Then in your terminal run the docker init command:

```
docker init
```

Docker init command will scan your project and ask you to choose the template that best fits your project.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/erpv6fjhwvcbgw3j6j3o.png)
After docker init is completed, you may need to modify the created files and tailor them to your projects.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dmr1d0kripo0aqdrdzl6.png)
>Note if any of the files exist, a prompt will appear and provide a warning as well as an option to overwrite all the files. You can't recover an overwritten file.

Let's see what the auto-generated Dockerfile looks like:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gha44dayuvbo4960s8x0.png)
### Conclusion
Creating a Dockerfile can be useful in the automation project or in development as it makes it easy to manage dependencies and system requirements for our application. Instead of having to worry about ensuring that your application has the correct versions of libraries and dependencies installed on the host system, we can easily specify them in the Dockerfile and they will be included in the container image.
This makes it easy to manage and control the dependencies of your application, and it also makes it easy to test your application on different environments. The Docker init command also helps to save time and effort and also write better Dockerfiles, but I would recommend you to cross check the configuration before you push through with it.
Hope you like the article. Thanks for reading!

Source code: https://github.com/Stefanie-A/docker-app-template.git