• 2,817 Views

How to start two containers exposed on the same port using same image but diff environment variable

Jump to solution

How to start two containers exposed on the same port using same image but diff environment variable. Both the containers must co-exist

Labels (2)
1 Solution

Accepted Solutions
Tracy_Baker
Starfighter Starfighter
Starfighter
  • 3,078 Views

You can do this, but the containers must be created as rootful containers - that is, either sudo must be used or the root account must create them.

Rootless containers, those created by a non-root account, do not get external IP addresses. They are accessed via port number, for example: http://localhost:8080 . As a result, If you try to create two containers with the same published ports, you get an error.

[student@rhel9-ws ~]$ podman run -d --name webserver1 -p 8080:8080 registry.fedoraproject.org/f29/httpd
e649fe53b732a28c36b02bffdada4e3b5f45327557144c2efe2cdf3f6f833b78

[student@rhel9-ws ~]$ podman run -d --name webserver2 -p 8080:8080 registry.fedoraproject.org/f29/httpd
Error: rootlessport listen tcp 0.0.0.0:8080: bind: address already in use

Also, notice that there is no IP address for the container that did start:

[student@rhel9-ws ~]$ podman inspect webserver1 | grep IPAdd
"IPAddress": "",

----

To make it work, do the same as root (or using sudo), but do not publish the ports:

[student@rhel9-ws ~]$ sudo podman run -d --name webserver1 registry.fedoraproject.org/f29/httpd
33788fb3cb92531dd4e4039f547d11d0cc8d75ce313356949ec793520b0e7e6c

[student@rhel9-ws ~]$ sudo podman run -d --name webserver2 registry.fedoraproject.org/f29/httpd
fca95a7ff45d9fd24d73d51b4d142f1a542f24f06d9f2c5a587370e187e7565b

So they both started. But how to access them? By using a socket that is the IP address they received (because they're rootful containers) and the port number that the service in the container uses:

[student@rhel9-ws ~]$ sudo podman inspect webserver1 | grep IPAdd
"IPAddress": "10.88.0.6",
"IPAddress": "10.88.0.6",

[student@rhel9-ws ~]$ sudo podman inspect webserver2 | grep IPAdd
"IPAddress": "10.88.0.7",
"IPAddress": "10.88.0.7",

To test and verify (I created index.html files and copied them into the containers)...

[student@rhel9-ws ~]$ curl 10.88.0.6:8080
SERVER 1

[student@rhel9-ws ~]$ curl 10.88.0.7:8080
SERVER 2

---

You also asked about environment variables. That is no big deal. Just include the -e <variable=value> where needed.

For example:

[student@rhel9-ws ~]$ sudo podman run -d --name webserver3 -e MYVAR3=firstname registry.fedoraproject.org/f29/httpd
f920a76d6d5b472d2d866826d46d17870da3a101ae5d9580473905a6c73a31a9

[student@rhel9-ws ~]$ sudo podman run -d --name webserver4 -e MYVAR3=firstname registry.fedoraproject.org/f29/httpd
1fb24d758c7f4fa10f326ab8d26c1d2d66e55200b6a1640c17f8a8a826f3d030

And checking to see if it was set.

[student@rhel9-ws ~]$ sudo podman exec webserver3 env | grep MYVAR3
MYVAR3=firstname

[student@rhel9-ws ~]$ sudo podman exec webserver4 env | grep MYVAR3
MYVAR3=firstname

Of course, more than one variable can be set and they do not need to be the same for the containers...

Program Lead at Arizona's first Red Hat Academy, est. 2005
Estrella Mountain Community College

View solution in original post

5 Replies
Tracy_Baker
Starfighter Starfighter
Starfighter
  • 3,079 Views

You can do this, but the containers must be created as rootful containers - that is, either sudo must be used or the root account must create them.

Rootless containers, those created by a non-root account, do not get external IP addresses. They are accessed via port number, for example: http://localhost:8080 . As a result, If you try to create two containers with the same published ports, you get an error.

[student@rhel9-ws ~]$ podman run -d --name webserver1 -p 8080:8080 registry.fedoraproject.org/f29/httpd
e649fe53b732a28c36b02bffdada4e3b5f45327557144c2efe2cdf3f6f833b78

[student@rhel9-ws ~]$ podman run -d --name webserver2 -p 8080:8080 registry.fedoraproject.org/f29/httpd
Error: rootlessport listen tcp 0.0.0.0:8080: bind: address already in use

Also, notice that there is no IP address for the container that did start:

[student@rhel9-ws ~]$ podman inspect webserver1 | grep IPAdd
"IPAddress": "",

----

To make it work, do the same as root (or using sudo), but do not publish the ports:

[student@rhel9-ws ~]$ sudo podman run -d --name webserver1 registry.fedoraproject.org/f29/httpd
33788fb3cb92531dd4e4039f547d11d0cc8d75ce313356949ec793520b0e7e6c

[student@rhel9-ws ~]$ sudo podman run -d --name webserver2 registry.fedoraproject.org/f29/httpd
fca95a7ff45d9fd24d73d51b4d142f1a542f24f06d9f2c5a587370e187e7565b

So they both started. But how to access them? By using a socket that is the IP address they received (because they're rootful containers) and the port number that the service in the container uses:

[student@rhel9-ws ~]$ sudo podman inspect webserver1 | grep IPAdd
"IPAddress": "10.88.0.6",
"IPAddress": "10.88.0.6",

[student@rhel9-ws ~]$ sudo podman inspect webserver2 | grep IPAdd
"IPAddress": "10.88.0.7",
"IPAddress": "10.88.0.7",

To test and verify (I created index.html files and copied them into the containers)...

[student@rhel9-ws ~]$ curl 10.88.0.6:8080
SERVER 1

[student@rhel9-ws ~]$ curl 10.88.0.7:8080
SERVER 2

---

You also asked about environment variables. That is no big deal. Just include the -e <variable=value> where needed.

For example:

[student@rhel9-ws ~]$ sudo podman run -d --name webserver3 -e MYVAR3=firstname registry.fedoraproject.org/f29/httpd
f920a76d6d5b472d2d866826d46d17870da3a101ae5d9580473905a6c73a31a9

[student@rhel9-ws ~]$ sudo podman run -d --name webserver4 -e MYVAR3=firstname registry.fedoraproject.org/f29/httpd
1fb24d758c7f4fa10f326ab8d26c1d2d66e55200b6a1640c17f8a8a826f3d030

And checking to see if it was set.

[student@rhel9-ws ~]$ sudo podman exec webserver3 env | grep MYVAR3
MYVAR3=firstname

[student@rhel9-ws ~]$ sudo podman exec webserver4 env | grep MYVAR3
MYVAR3=firstname

Of course, more than one variable can be set and they do not need to be the same for the containers...

Program Lead at Arizona's first Red Hat Academy, est. 2005
Estrella Mountain Community College
  • 2,920 Views

Thanks for the reply !

Kwakou-Steve
Mission Specialist
Mission Specialist
  • 2,746 Views

Hello, I don't really get the reason behind accessing two containers on the same ports. That seems like an anti-pattern. Why wouldn't you use port forwading ?
Unless you don't want to expose the ports and are doing solely host to container communication or container to container communication within the same host.
But even for that, there are better solutions like podman-compose and DNS enabled networks shared by the containers.
I would also like to add to Tracy_Baker response that rootless containers could get IP addresses: you need to attach them to a container network. So, no need for privilege elevation to implement the solution he suggested.
And something else (not related): I think it is best to use this:
podman exec webserver3 printenv MYVAR3
instead of this:
podman exec webserver3 env | grep MYVAR3
Recall we are dealing limited resources when using containers: save some cpu cycles by avoiding pipes and grep when possible !

 

 

 

 

Tracy_Baker
Starfighter Starfighter
Starfighter
  • 1,519 Views

Second point first:

podman exec webserver3 env | grep MYVAR3

This does not run grep inside the container. No CPU cycles - inside the container - are being used.

Your command works just fine, of course. Here's the difference between the two:

Tracy_Baker_0-1704122050605.png

So it really depends on what you want the output to look like.

-----

To the first point, "I would also like to add to Tracy_Baker response that rootless containers could get IP addresses: you need to attach them to a container network. So, no need for privilege elevation to implement the solution he suggested."

Connecting a rootless container to a container network does not expose the IP address to the host. As a result, the rootless container cannot be accessed via IP. For example:

A container (tracy_webserver) is connected to the tracy_baker container network.

podman run -d --name tracy_webserver --network tracy_baker -p 8080:8080 \
registry.redhat.io/ubi9/httpd-24

It has an IP address:

Tracy_Baker_1-1704122255913.png

However, it cannot be access using that IP address (the Apache webserver in the container is listening on port 8080):

Tracy_Baker_2-1704122320194.png

It can be accessed via the host using the published port (port forwarding):

Tracy_Baker_3-1704122360461.png

OK... so what's the container network's purpose (at least in this scenario)? It is to allow containers, which are attached to the same internal container network, to communicate.

I created a second container, using a UBI and installing iputils, and connected it to the tracy_baker container network:

podman run -d --name tracy_ubi --network tracy_baker registry.redhat.io/ubi9/ubi \
tail -f /etc/os-release

Checking to see if it has an IP address:

Tracy_Baker_4-1704122840629.png

Can the host ping the Apache container? (That'd be no.)

Tracy_Baker_6-1704122987133.png

However, can the UBI container ping the Apache container? (That'd be yes and, incidentally, DNS is working...)

Tracy_Baker_7-1704123044073.png

-----

Back to the OP's original question, "How to start two containers exposed on the same port using same image but diff environment variable. Both the containers must co-exist"

To do this requires the use of rootful containers as they get IP addresses that are exposed to the host, unlike container networks. As a result, the same port number can be used for both containers as the socket that will be used to communicate to the contatiner process will have a different IP address.

Program Lead at Arizona's first Red Hat Academy, est. 2005
Estrella Mountain Community College
Travis
Moderator
Moderator
  • 1,504 Views

Actually, you cannot get two containers bound to the same port on workstation on a publicly addressable IP address. The workstation system is 172.25.250.9 and using Port Forward will occupy the port on that subnet.

You can use either Rootful or Rootless containers as Podman supports a larger conainter network. This will allow connectivity to the containers via DNS hostnames on the containerized network and the workstation machine has access to those networks.

Port Forwarding: https://rol.redhat.com/rol/app/courses/do188-4.12/pages/ch02s05

Not directly related but good links about container networking and DNS:

https://learn.redhat.com/t5/DO188-Red-Hat-OpenShift/How-to-overwrite-podman-network-to-enable-DNS/m-...

 

You can run multiple containers from a single Base image (container image) using multiple different environment variables for each container. The harder part of the question is the same port. There are many good answers here, but there are some additional things to understand.

In terms of the Podman networks (container only networks - local to workstation) ...

It is possible to create different container networks using Podman networks (https://rol.redhat.com/rol/app/courses/do188-4.12/pages/ch02s03) and these networks allow containers to interact with each other by default via hostnames. The workstation machine can access these containers based on the ports and there is also no need to port-forward as the workstation has a network connection on each of the individual container networks that has been created.

So the REAL Question ... Can you access containers with port forward using the same port?

Yes, it would be possible, although you would need to setup the host-based firewall with FirewallD correctly and you would also need to have multiple public IP addresses on the Workstation (container hosting) machine. That means workstation would need to have another IP address on an accessible/routable network other than the single 172.25.250.9. When using port-forward you would not only need to specify the port, but also the IP address that you want it to forward to. You CANNOT expose the same port to multiple containers on listening on the same IP address. Only a single address and port can be bound to a single container. 

Additionally, there are concerns that if you are wanting to forward a port below 1024. Then you need to either make it a container with "root" privileges to bind to that port or there are things you can do to allow a rootless container to be bound to port 80 (again possible, but takes a little bit of work).

Kubernetes/OpenShift or NginX Proxy

Again, as some people have mentioned, generally port forwarding and redirection is used. However, the assumption is based on the question you might want to have two different webserver containers both running on port 80/443 so you don't need to worry about ports with the URLs. This is where Kubernetes and more specifically OCP routes can help. If you are using something like Podman/Docker alone, then you can create the NGINX Proxy container that is bound to ports 80/443 and then the other containers you have at various ports and configure the proxy to look at the "names" to route the request to the appropriate ports.

 

 

Travis Michette, RHCA XIII
https://rhtapps.redhat.com/verify?certId=111-134-086
SENIOR TECHNICAL INSTRUCTOR / CERTIFIED INSTRUCTOR AND EXAMINER
Red Hat Certification + Training
Join the discussion
You must log in to join this conversation.