Baeldung Pro – Ops – NPI EA (cat = Baeldung on Ops)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

Partner – Orkes – NPI EA (cat=Kubernetes)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

1. Introduction

Podman is an open-source container management tool with a Docker-compatible command line interface for managing containers and container images. It uses Open Container Initiative (OCI) standards to ensure compatibility with other container technologies.

Most Docker commands work with Podman, making it easier for Docker users to transition. Since Podman is OCI compliant, it can work with container images stored in the Docker registry, as they both use the OCI image format. Podman can push and pull images from the Docker registry without any special configuration.

In this tutorial, we’ll learn how to push images to the Docker registry using Podman.

All commands in this tutorial have been tested on Ubuntu 22.04.

2. Prerequisites

Before pushing a container image to a Docker registry, we should have Podman on the machine.

To verify the installation, we run the podman –version command in the terminal:

$ podman --version
podman version 3.4.4

If not installed, the package is available on Ubuntu (after 20.10) and Debian official repositories:

$ sudo apt-get update
$ sudo apt-get -y install podman

On the other hand, a Podman installer is recommended for Mac and Windows machines.

Additionally, possessing a Docker registry account (e.g., Docker Hub, Quay.io) is mandatory for pushing images. We use Docker Hub for this tutorial.

3. Create a Simple NodeJS Application

First, we install NodeJS on the machine. We can install it directly from the official apt repositories:

$ sudo apt install nodejs

Now, we can create the application.

Initially, we create a directory named podman-node-server and navigate into it:

$ mkdir -p ~/podman-node-server
$ cd ~/podman-node-server

Next, let’s initialize npm and install the express package:

$ npm init -y
$ npm install express

Then, we create a server.js file that builds a Web server that runs on port 3000:

$ cat ~/podman-node-server/server.js 
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello, Podman! This is Baeldung');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

Furthermore, let’s update the package.json file created by default on initialization to include a start script in the scripts section:

$ cat ~/podman-node-server/package.json
{
  "name": "podman-node-server",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "keywords": [],
  "author": "",
  ...
  }
}

To confirm whether the NodeJS application is functional, we can run the server locally using the npm start command:

$ npm start

> [email protected] start
> node server.js

Server running at http://localhost:3000

Using a browser, we access the server through localhost on port 3000:

NodeJS server running locally

Alternatively, we can use the curl command:

$ curl localhost:3000
Hello, Podman! This is Baeldung

Hence, we’ve successfully created the NodeJS application and verified its function.

4. Build a Dockerfile Image With Podman

Podman offers excellent compatibility with the Dockerfile mechanism, making it easier for users familiar with Docker to transition to Podman.

Podman can build images directly from a Dockerfile without any modifications. The syntax and instructions used for Dockerfiles are fully supported.

In fact, Podman uses a similar build command to Docker:

podman build -t <imagename:tag> .

This command works the same way as the docker build command.

Furthermore, Podman supports a lot of Docker features:

  • all standard Dockerfile instructions (FROM, RUN, COPY, ADD, ENV, and similar)
  • multistage builds
  • many advanced features introduced by Docker’s BuildKit, such as build secrets and SSH forwarding
  • build-time variables (ARG instructions)
  • same base images specified in Dockerfiles, including official Docker Hub images
  • interpreting VOLUME and EXPOSE instructions in Dockerfiles

Let’s create a Dockerfile in the project directory (~/podman-node-server) to containerize the NodeJS application:

$ cat Dockerfile
FROM node:14

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

CMD [ "node", "server.js" ]

This Dockerfile specifies node:14 as the base image for the new Docker container. This provides us with a pre-configured environment with NodeJS installed.

It then sets the working directory inside the container to /usr/src/app and copies the package.json and package-lock.json files from the local directory to the container’s working directory. This is executed before running the npm install command to take advantage of Podman’s caching mechanism for faster builds.

Lastly, the instructions copy all the files and directories from the local project directory to the container’s working directory and then exposes port 3000 at runtime. The CMD arguments specify the command to run when the container starts. In this case, it runs node server.js to start the NodeJS server.

Let’s build the container image:

$ podman build -t podman-node-server:latest .

Once the build is complete, we verify the image creation using the podman images command

$ podman images
REPOSITORY                    TAG         IMAGE ID      CREATED        SIZE
localhost/podman-node-server  latest      6bc75f05e543  2 days ago     946 MB
docker.io/library/node        14          1d12470fa662  17 months ago  937 MB

As seen in the output above, the podman-node-server image has been created.

5. Push the Image to Docker Hub

Before we push the image to Docker Hub, we can run the image locally to be sure the build is correct. Let’s create a container from the image using the podman run command:

$ podman run -d -p 3000:3000 podman-node-server
1a95f9d4571a2631e175794b63bb40f5933cd079f08a51fd948a0c3d464ee846

Podman creates and starts a container based on the postman-node-server image in detached mode. It then maps port 3000 from inside the container to port 3000 on the host machine. The NodeJS server inside the container starts running. We can confirm this using the curl command or Web browser.

Also, we can verify the container status using the podman ps command:

$ podman ps
CONTAINER ID  IMAGE                                COMMAND         CREATED         STATUS             PORTS                   NAMES
1a95f9d4571a  localhost/podman-node-server:latest  node server.js  10 seconds ago  Up 11 seconds ago  0.0.0.0:3000->3000/tcp  adoring_banzai

Hence, the image build is correct and functions appropriately. We can now push the image to Docker Hub.

To begin, let’s log in with the proper credentials using the podman login command:

$ podman login docker.io
Username: ****
Password:

As seen above, the command prompts us to enter the correct username and password for Docker Hub.

Once the login is successful, we can push the image to Docker Hub using the podman push command. It has a fairly simple usage syntax:

podman push <IMAGE_ID> docker://docker.io/<username>/<imagename>

So, let’s push the podman-node-server image:

$ podman push 6bc75f05e543 docker://docker.io/afkzoro/podman-node-server

After the push is complete, we can verify the image’s publication on the Docker Hub website:

podman-node-server image on Docker Hub website

Alternatively, using the CLI, we can list the images in the registry via the podman search command:

$ podman search docker.io/<username>
INDEX       NAME                                  DESCRIPTION  STARS       OFFICIAL    AUTOMATED
docker.io   docker.io/<username>/python-hello-world               0                       
docker.io   docker.io/<username>/podman-node-server               0                       

Hence, we’ve successfully pushed an image to Docker Hub using Podman.

5. Conclusion

In this article, we’ve covered the essential aspects of working with Podman to build, push, and run containerized applications, particularly focusing on a NodeJS server. Additionally, we published the image to a Docker registry.

In conclusion, Podman provides a daemonless container engine compatible with Docker which can be used in much the same way but with added features.