DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • OpenAPI From Code With Spring and Java: A Recipe for Your CI
  • Solving the Mystery: Why Java RSS Grows in Docker on M1 Macs
  • Java Backend Development in the Era of Kubernetes and Docker
  • Java in a Container: Efficient Development and Deployment With Docker

Trending

  • DevOps and Platform Engineering Readiness Checklist: Everything Needed for a Scalable, Secure, High-Velocity Delivery Platform
  • Docker Hardened Images Are Free Now — Here's What You Still Need to Build
  • Integrating AI-Driven Decision-Making in Agile Frameworks: A Deep Dive into Real-World Applications and Challenges
  • How AI Is Rewriting Full-Stack Java Systems: Practical Patterns with Spring Boot, Kafka and WebSockets
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. DevOps and CI/CD
  4. Using the Ubuntu Docker Image

Using the Ubuntu Docker Image

In this post, we'll show you how to make the most of the base Ubuntu images while building your own Docker images and more!

By 
Matthew Casperson user avatar
Matthew Casperson
·
Dec. 14, 23 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
7.4K Views

Join the DZone community and get the full member experience.

Join For Free

The official Ubuntu Docker image is the most downloaded image from Docker Hub. With over one billion downloads, Ubuntu has proven itself to be a popular and reliable base image on which to build your own custom Docker images.

In this post, I show you how to make the most of the base Ubuntu images while building your own Docker images.

An Example Dockerfile

This is an example Dockerfile that includes the tweaks discussed in this post. I go through each of the settings to explain what value they add:

Dockerfile
 
FROM ubuntu:22.04
RUN echo 'APT::Install-Suggests "0";' >> /etc/apt/apt.conf.d/00-docker
RUN echo 'APT::Install-Recommends "0";' >> /etc/apt/apt.conf.d/00-docker
RUN DEBIAN_FRONTEND=noninteractive \
  apt-get update \
  && apt-get install -y python3 \
  && rm -rf /var/lib/apt/lists/*
RUN useradd -ms /bin/bash apprunner
USER apprunner


Build the image with the command:

Shell
 
docker build . -t myubuntu


Now that you've seen how to build a custom image from the Ubuntu base image, let's go through each of the settings to understand why they were added.

Selecting a Base Image

Docker images are provided for all versions of Ubuntu, including Long Term Support (LTS) releases such as 20.04 and 22.04, and normal releases like 19.04, 19.10, 21.04, and 21.10.

LTS releases are supported for 5 years, and the associated Docker images are also maintained by Canonical during this period, as described on the Ubuntu release cycle page:

These images are also kept up to date, with the publication of rolled up security updated images on a regular cadence, and you should automate your use of the latest images to ensure consistent security coverage for your users.

When creating Docker images hosting production software, it makes sense to base your images on the latest LTS release. This allows DevOps teams to rebuild their custom images on top of the latest LTS base image, which automatically includes all updates but is also unlikely to include the kind of breaking changes that can be introduced between major operating system versions.

I used the Ubuntu 22.04 LTS Docker image as the base for this image:

Shell
 
FROM ubuntu:22.04


Not Installing Suggested or Recommended Dependencies

Some packages have a list of suggested or recommended dependencies that aren't required but are installed by default. These additional dependencies can add to the size of the final Docker image unnecessarily, as Ubuntu notes in their blog post about reducing Docker image sizes.

To disable the installation of these optional dependencies for all invocations of apt-get, the configuration file at /etc/apt/apt.conf.d/00-docker is created with the following settings:

Shell
 
RUN echo 'APT::Install-Suggests "0";' >> /etc/apt/apt.conf.d/00-docker
RUN echo 'APT::Install-Recommends "0";' >> /etc/apt/apt.conf.d/00-docker


Installing Additional Packages

Most custom images based on Ubuntu require you to install additional packages. For example, to run custom applications written in Python, PHP, Java, Node.js, or DotNET, your custom image must have the packages associated with those languages installed.

On a typical workstation or server, packages are installed with a simple command like:

Shell
 
apt-get install python3


The process of installing new software in a Docker image is non-interactive, which means you don't have an opportunity to respond to prompts. This means you must add the -y argument to automatically answer "yes" to the prompt asking to continue with the package installation:

Shell
 
RUN apt-get install -y python3


Preventing Prompt Errors During Package Installation

The installation of some packages attempts to open additional prompts to further customize installation options. In a non-interactive environment, such as during the construction of a Docker image, attempts to open these dialogs result in errors like:

Shell
 
unable to initialize frontend: Dialog


These errors can be ignored as they don't prevent the packages from being installed. But the errors can be prevented by setting the DEBIAN_FRONTEND environment variable to noninteractive:

Shell
 
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python3


The Docker website provides official guidance on the use of the DEBIAN_FRONTEND environment variable. They consider it a cosmetic change and recommend against permanently setting the environment variable. The command above sets the environment variable for the duration of the single apt-get command, meaning any subsequent calls to apt-get will not have the DEBIAN_FRONTEND defined.

Cleaning Up Package Lists

Before any packages can be installed, you need to update the package list by calling:

Shell
 
RUN apt-get update


However, the package list is of little value after the required packages have been installed. It's best practice to remove any unnecessary files from a Docker image to ensure the resulting image is as small as it can be. To clean up the package list after the required packages have been installed, the files under /var/lib/apt/lists/ are deleted.

Here you update the package list, install the required packages, and clean up the package list as part of a single command, broken up over multiple lines with a backslash at the end of each line:

Shell
 
RUN DEBIAN_FRONTEND=noninteractive \
  apt-get update \
  && apt-get install -y python3 \
  && rm -rf /var/lib/apt/lists/*


Run as a Non-Root User

By default, the root user is run in a Docker container. The root user typically has far more privileges than are required when running a custom application, so creating a new user without root privileges provides better security.

The useradd command provides a non-interactive way to create new users.

This isn't to be confused with the adduser command, which is a higher-level wrapper over useradd.

After all configuration files have been edited and packages have been installed, you create a new user called apprunner:

Shell
 
RUN useradd -ms /bin/bash apprunner


This user is then set as the default user for any further operations:

Shell
 
USER apprunner


Conclusion

It's possible to use the base Ubuntu Docker images with little customization beyond installing any required additional packages. But with a few tweaks to limit optional packages from being installed, cleaning up package lists after the packages are installed, and creating new users with limited permissions to run custom applications, you can create smaller and more secure images for your custom applications.

Learn how to use other popular container images:

  • Using the NGINX Docker image
  • Using the Alpine Docker image

Resources

  • Ubuntu Docker image
  • Dockerfile reference

Happy deployments!

IT Docker (software) operating system ubuntu DevOps Java (programming language) Python (language)

Published at DZone with permission of Matthew Casperson. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • OpenAPI From Code With Spring and Java: A Recipe for Your CI
  • Solving the Mystery: Why Java RSS Grows in Docker on M1 Macs
  • Java Backend Development in the Era of Kubernetes and Docker
  • Java in a Container: Efficient Development and Deployment With Docker

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook