- 1 1. Introduction
- 2 2. Basic Structure of a Dockerfile
- 3 3. Practice: Creating an Ubuntu-Based Dockerfile
- 4 4. Building and Verifying the Docker Image
- 5 5. Application: Building a Python Environment
- 6 6. Common Issues and Solutions
- 7 7. Conclusion
- 8 8. FAQ (Frequently Asked Questions)
- 8.1 Q1. Which version of Ubuntu should I choose in my Dockerfile?
- 8.2 Q2. Why do I get “Package not found” when using apt-get install?
- 8.3 Q3. How do I set environment variables in a Dockerfile?
- 8.4 Q4. What is the difference between CMD and ENTRYPOINT in a Dockerfile?
- 8.5 Q5. I edited my Dockerfile, but the changes are not reflected. Why?
1. Introduction
What are Docker and Dockerfile?
In recent years, Docker has rapidly gained popularity as a means to streamline the setup of development environments and the deployment of applications. Docker has the unique ability to package an application and its dependencies into a single “container,” which can then be run in the same environment anywhere.
To build this Docker container, a blueprint called “Dockerfile” is necessary. A Dockerfile is a text file that specifies the base OS image, software to be installed, environment variable settings, and more. Developers can use this file to automatically build customized environments.
Reasons for Choosing Ubuntu as the Base
When creating a Dockerfile, the first step is to specify the base OS image. Among the many options, Ubuntu is particularly popular. Ubuntu is a Debian-based Linux distribution known for its ease of use and the flexibility to build diverse environments thanks to its extensive package repository.
A Dockerfile based on Ubuntu offers the following advantages:
- Abundant official and community documentation is available, resulting in a lower learning curve.
- Many packages and tools can be easily installed using APT (Advanced Package Tool).
- Lightweight minimal images (such as
ubuntu:20.04
,ubuntu:24.04
) are officially provided.
Purpose and Target Audience of This Article
In this article, we will focus on the keyword “Dockerfile Ubuntu” and provide an easy-to-understand explanation for beginners on how to create Ubuntu-based Dockerfiles.
Specifically, we will comprehensively cover everything from the basic structure of a Dockerfile to the steps for actually building an Ubuntu environment, examples of installing application environments like Python, and common errors with their solutions.
This article is recommended for:
- Those who want to build an environment using Dockerfile for the first time.
- Those who want to create a reproducible development environment on Ubuntu.
- Those who want to deepen their knowledge, including how to troubleshoot issues.
2. Basic Structure of a Dockerfile
What is a Dockerfile? Understanding Its Role
A Dockerfile is like a recipe for creating a Docker image. Specifically, it’s a text file that describes which base OS to use, what software to install, and what configurations to apply.
By executing the docker build
command using this file, you can easily build highly reproducible development and application execution environments.
Benefits of using Dockerfile:
- Automation of environment setup (no need to reproduce manual steps).
- Eliminates environment inconsistencies when developing with multiple team members.
- Easy to integrate into CI/CD pipelines.
Commonly Used Basic Instructions (Directives) in Dockerfile
A Dockerfile contains several instructions (directives), with the following being the most representative. We will combine these appropriately to create an Ubuntu-based Dockerfile.
Instruction | Description |
---|---|
FROM | Specifies the base Docker image. Example: FROM ubuntu:24.04 |
RUN | Executes shell commands. Used for package installation, etc. |
COPY | Copies local files into the image. |
ADD | Similar to COPY, but also allows fetching from URLs and extracting archives. |
WORKDIR | Sets the working directory. |
ENV | Sets environment variables. |
CMD | Defines the command to be executed when the container starts (can be overridden). |
ENTRYPOINT | Similar to CMD, but defines a command that is always executed. |
Minimal Example of an Ubuntu-Based Dockerfile
Below is a very basic example of a Dockerfile based on Ubuntu.
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y
curl
vim
CMD ["/bin/bash"]
This Dockerfile is configured to use Ubuntu 24.04 as the base, install two utilities (curl
and vim
), and finally start the bash shell.
About Selecting Ubuntu Tags
Ubuntu Docker images are available on the official Docker Hub repository. While specifying ubuntu:latest
will use the newest version, it is recommended to explicitly pin a version.
For example:
ubuntu:22.04
(LTS: Long Term Support version, emphasizes stability)ubuntu:24.04
(Latest LTS candidate, emphasizes features)
Consider whether to prioritize stability or new features depending on your purpose.
3. Practice: Creating an Ubuntu-Based Dockerfile
Installing Necessary Packages for the Ubuntu Environment
When building an Ubuntu environment using Dockerfile, you will often need to install additional packages. For example, the following utilities are commonly used to set up a development environment:
curl
: For fetching files and checking APIs.vim
: A simple text editor.git
: A version control tool.build-essential
: A collection of basic tools necessary for building C/C++ programs.
To install these in a Dockerfile, use the RUN
instruction.
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y
curl
vim
git
build-essential
By running apt-get update
first, you ensure that the latest package lists are obtained before installation.
Setting Up Non-Interactive Installation
In Ubuntu, apt-get install
may require user input, but interactive operations are not possible during the Docker build process. Therefore, it is recommended to set the environment variable as follows to perform the installation in non-interactive mode.
ENV DEBIAN_FRONTEND=noninteractive
This will skip prompts such as “Regional Settings” that appear during package configuration, allowing the installation to proceed smoothly.
Reducing Image Size by Removing Unnecessary Cache
When using APT, downloaded temporary files (cache) can remain in the image, making the final Docker image larger. You can reduce the image size by deleting this cache as follows:
RUN apt-get update && apt-get install -y
curl
vim
&& rm -rf /var/lib/apt/lists/*
By combining multiple commands into a single RUN
statement like this, you can also prevent the creation of unnecessary layers.
Best Practices: Organizing Your Dockerfile
In actual development environments, the following best practices for writing Dockerfiles are recommended:
- Combine
RUN
instructions as much as possible to reduce the number of layers. - Explicitly define versions and configurations using
ENV
. - Use comments to clearly state the purpose of each operation.
- Use
rm
and--no-install-recommends
to avoid leaving unnecessary files.
Example:
RUN apt-get update && apt-get install -y --no-install-recommends
curl
git
&& rm -rf /var/lib/apt/lists/*
By doing this, you can build a more lightweight and maintainable Dockerfile.
4. Building and Verifying the Docker Image
Building a Docker Image from a Dockerfile
Once you have written your Dockerfile, the next step is to build the Docker image. This is done using the docker build
command. Execute the following command in the directory where your Dockerfile is located:
docker build -t my-ubuntu-image .
- The
-t
option is used to give the image a name (tag). In this example, we are naming itmy-ubuntu-image
. - The
.
refers to the current directory where the Dockerfile is located.
When you run this command, Docker will sequentially read the instructions in the Dockerfile and build a new image accordingly.
Verifying the Built Docker Image
After the image creation is complete, you can verify it with the following command:
docker images
This will display a list of Docker images that exist locally, and you can check the following information:
- REPOSITORY (image name)
- TAG (tag)
- IMAGE ID (unique identifier)
- CREATED (creation date and time)
- SIZE (size)
Example:
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ubuntu-image latest abcd1234abcd 5 minutes ago 189MB
This confirms that the image you created has been successfully registered.
Starting a Docker Container and Verifying Operation
To verify that the created image functions correctly, let’s start a Docker container. Use the following command:
docker run -it my-ubuntu-image
- Specifying the
-it
option allows you to start a terminal in interactive mode. - If it starts successfully, a bash prompt within the container will appear, and you will bein a state as if you have logged into an Ubuntu environment.
Inside the container, you can execute commands like the following to check if the installed tools are working correctly:
curl --version
vim --version
If there are no issues, the Dockerfile has been written successfully.
Cleaning Up Unnecessary Images and Containers
As you repeat builds and experiments, unnecessary Docker images and containers may accumulate locally. It is recommended to periodically clean them up using commands like the following:
- Deleting stopped containers:
docker container prune
- Deleting unused images:
docker image prune
- Deleting all unused data (Caution!):
docker system prune
These operations help to save disk space and prevent issues.
5. Application: Building a Python Environment
Making Python Usable in an Ubuntu-Based Dockerfile
By adding a Python execution environment when building an Ubuntu environment using Dockerfile, you can support a wide range of uses such as development, testing, and machine learning. While Ubuntu may have Python pre-installed, it is common practice to explicitly build it yourself from the perspective of version and package management.
How to Install Python Using apt
The simplest way is to install Python using APT packages. Here’s an example:
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y
python3
python3-pip
&& rm -rf /var/lib/apt/lists/*
With this method, you can use the stable version of Python installed on the system (usually Python 3.10 or 3.12, etc.). In addition, you can add Python packages using the pip
command.
Managing Python Versions with pyenv
If you want to use a specific Python version or switch between multiple versions, using pyenv is convenient.
Below is an example of using pyenv to install Python 3.11.6 in a Dockerfile:
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y
git
curl
make
build-essential
libssl-dev
zlib1g-dev
libbz2-dev
libreadline-dev
libsqlite3-dev
wget
llvm
libncurses5-dev
libncursesw5-dev
xz-utils
tk-dev
libffi-dev
liblzma-dev
&& rm -rf /var/lib/apt/lists/*
# Install pyenv
RUN git clone [https://github.com/pyenv/pyenv.git](https://github.com/pyenv/pyenv.git) ~/.pyenv
ENV PYENV_ROOT="$HOME/.pyenv"
ENV PATH="$PYENV_ROOT/bin:$PATH"
RUN echo 'eval "$(pyenv init --path)"' >> ~/.bashrc
# Install a specific Python version
RUN pyenv install 3.11.6 && pyenv global 3.11.6
This allows you to build and manage your Python environment more flexibly.
Package Management Using requirements.txt
In actual projects, you will often need multiple Python libraries. requirements.txt
is used to manage these.
First, prepare a requirements.txt
file in the root directory of your project:
flask==2.3.2
requests>=2.25.1
pandas
Next, describe it in the Dockerfile as follows:
COPY requirements.txt /app/requirements.txt
WORKDIR /app
RUN pip install --no-cache-dir -r requirements.txt
This allows you to install the necessary libraries all at once, increasing the reproducibility of your development environment.
Best Practices
- When using Python, building a virtual environment with
virtualenv
orvenv
can help prevent dependency conflicts. - You can reduce the size of your Docker image by deleting the cache (
--no-cache-dir
). - Installing the latest version of pip with
pip install --upgrade pip
before installing Python packages can prevent errors.
6. Common Issues and Solutions
Permission Errors
Example:
Permission denied
This occurs when the copied file does not have execute permissions or when the file owner/executing user is not appropriate.
Solutions:
- Make the file executable:
RUN chmod +x script.sh
- Change the user if necessary:
RUN chown root:root /path/to/file
Package Not Found or Cannot Be Installed
Example:
E: Unable to locate package xxx
This error occurs when apt-get update
has not been run or when the specified package name is incorrect.
Solutions:
- Always write
apt-get update
beforeinstall
:
RUN apt-get update && apt-get install -y curl
- Check the package name for typos and ensure it is correct.
Network-Related Errors
Example:
Temporary failure resolving 'deb.debian.org'
This type of error occurs when DNS resolution fails during the build process.
Solutions:
- Restarting the Docker daemon may resolve the issue:
sudo systemctl restart docker
- Review the Docker DNS settings (add DNS specifications to
/etc/docker/daemon.json
):
{
"dns": ["8.8.8.8", "8.8.4.4"]
}
Build Remains in an Old State Due to Cache Effects
Docker uses a layer-by-layer cache for speed. As a result, even if you modify the Dockerfile, it may not build as intended because cached layers are being reused.
Solution:
- Rebuild without using the cache:
docker build --no-cache -t my-image .
Startup Command in Container Fails to Execute or Exits Immediately
Causes:
- The command specified in
CMD
orENTRYPOINT
is encountering an error. - Even if you specify
["/bin/bash"]
inCMD
, it will exit immediately if not run interactively.
Solutions:
- Start the container for debugging and check:
docker run -it my-image /bin/bash
- Understand the difference between
CMD
andENTRYPOINT
and use them appropriately for your purpose.
By experiencing these issues, your Dockerfile design skills will definitely improve. When you encounter a problem, calmly read the error message and carefully trace which layer or instruction is the cause.
7. Conclusion
Reconfirming Key Points for Creating Ubuntu-Based Dockerfiles
In this article, we have explained step-by-step from basic to applied methods on how to build an Ubuntu environment using Dockerfile. Let’s reiterate the important points here.
- Understanding the basic structure of a Dockerfile is the first step.
You can automate environment setup by combining instructions such asFROM
,RUN
,CMD
, andENV
. - Ubuntu is a stable and highly flexible base image.
Its rich package repository, large user base, and the availability of LTS versions make it suitable as a foundation for development environments. - You can install necessary tools and libraries through practical package management.
Knowing how to useapt-get
, remove cache, and perform non-interactive installations are key. - Building practical environments like Python is also possible with Dockerfile.
Tools likepyenv
,pip
, andrequirements.txt
enable you to create highly reproducible development environments. - Troubleshooting skills directly lead to stable operation.
Understanding common pitfalls such as permissions, network issues, and build cache can significantly improve development efficiency.
Next Steps for Learning Dockerfile
Being able to handle Dockerfiles allows you to support a wide range of uses, not only in development but also in testing and deploying to production environments. For future learning, it would be beneficial to move on to the following topics:
- Managing multi-container configurations using Docker Compose.
- Integration with CI/CD tools (GitHub Actions, GitLab CI, etc.).
- Interoperation with container orchestration tools such as Kubernetes.
8. FAQ (Frequently Asked Questions)
Q1. Which version of Ubuntu should I choose in my Dockerfile?
A1. Basically, if you prioritize stability and long-term support, it is common to choose an LTS (Long Term Support) version. For example, ubuntu:22.04
and ubuntu:20.04
are used in many development environments and can be used with confidence due to their 5-year support period.
On the other hand, if you want to use the latest packages and language versions, you can choose a newer release like ubuntu:24.04
, but we recommend testing it beforehand.
Q2. Why do I get “Package not found” when using apt-get install
?
A2. The most common reason is that you have not run apt-get update
beforehand. If you try to install without updating the package list, you will get an error because the corresponding package cannot be found in the outdated list.
Correct usage example:
RUN apt-get update && apt-get install -y curl
Also, be careful about typos in package names and deprecated package names (e.g., python3
instead of python
).
Q3. How do I set environment variables in a Dockerfile?
A3. You set environment variables using the ENV
instruction. This environment variable will be valid during both the build and container runtime.
Example:
ENV DEBIAN_FRONTEND=noninteractive
This is a typical setting used to suppress interactive prompts during APT installation. It is also used to set application configurations and API keys within the Dockerfile.
Q4. What is the difference between CMD
and ENTRYPOINT
in a Dockerfile?
A4. Both specify commands to be executed when the container starts, but there are differences in their usage and behavior.
Item | CMD | ENTRYPOINT |
---|---|---|
Overridable | Can be overridden by the docker run command | Basically not overridden (treated as arguments) |
Usage | Sets the default execution command | Defines a command that should always be executed |
Example:
CMD ["python3", "app.py"]
# vs
ENTRYPOINT ["python3"]
CMD ["app.py"]
In the latter case, you can pass the CMD
as an argument in the form of docker run my-image another_script.py
.
Q5. I edited my Dockerfile, but the changes are not reflected. Why?
A5. Docker uses cache during the build process, so even if you make small changes to the Dockerfile, cached layers may still be used.
Solution:
docker build --no-cache -t my-image .
This will perform a new build without using the cache, and all changes will be reflected.