Docker Community Forums

Share and learn in the Docker community.

Combine 2 dockerfiles with docker compose (tomcat + postgresql)

Hi everyone,
I’ve been using this code for a long time and I’m very satisfied because it works wonderfully.
Is there any way to rewrite everything using Docker-Composer?
Could I ask you for the code of the docker-compose.yml?
See you soon

Tomcat

FROM tomcat:9-jre11
LABEL Author="Nome Cognome"
EXPOSE 8080
RUN rm -fr /usr/local/tomcat/webapps/ROOT
COPY ./*.war /usr/local/tomcat/webapps/ROOT.war
CMD ["catalina.sh", "run"]
docker build -t tomcat-eb:v.9.0.17 .
docker run -it --rm --name tomcat-eb-container -p 8888:8080 tomcat-eb:v.9.0.17

Postgresql

FROM kartoza/postgis:9.6-2.4
LABEL Author="Nome Cognome"
EXPOSE 5432
VOLUME create pg_data
docker build -t tomcat-postgresql-postgis:v.9.0.17-9.6-2.4 .
docker run --name=postgresql-postgis-container -d -e POSTGRES_USER=eb -e POSTGRES_PASS=password -e POSTGRES_DBNAME=gis -e ALLOW_IP_RANGE=0.0.0.0/0 -p 5432:5432 -v pg_data:/var/lib/postgresql --restart=always tomcat-postgresql-postgis:v.9.0.17-9.6-2.4
docker run -it --rm --name tomcat-container -p 8888:8080 tomcat-postgresql-postgis:v.9.0.17-9.6-2.4

You would need to move everything under one folder to use docker compose. Since there can be only one file named Dockerfile in a folder you would need to rename one of them or move the Postgres Dockerfile into a subfolder. In the example I give below, I assume it is under a folder called ./postgresql

All you need to do then is look up the parameters that you are using for your command line invocation and specify them as attributes in the docker-compose.yaml file.

This should do what you want:

---
version: '3.7'
services:
  tomcat_eb:
    build: .
    image: tomcat-eb:v.9.0.17
    container_name: tomcat-eb-container
    ports:
      - 8888:8080
    restart: on-failure
    depends_on:
      - postgresql
    networks:
      - eb

  postgresql:
    build: ./postgresql
    image: tomcat-postgresql-postgis:v.9.0.17-9.6-2.4
    container_name: postgresql-postgis-container
    ports:
      - 5432:5432
    volumes:
      - pg_data:/var/lib/postgresql
    environment:
      POSTGRES_USER: "eb"
      POSTGRES_PASS: "password"
      POSTGRES_DBNAME: "gis"
      ALLOW_IP_RANGE: "0.0.0.0/0"
    restart: always
    networks:
      - eb

volumes:
  pg_data:

networks:
  eb:

You probably want to create a .dockerignore file and ignore the ./postgresql folder so that it doesn’t get included in the tomcat image.

1 Like

First of all, thank you for your contribution.
If I type “docker-compose up” I get this error:

…>docker-compose up
ERROR: In file ‘.\docker-compose.yaml’, service ‘version’ must be a mapping not a string.

I do not understand the “.dockerignore” speech.
With 2 Dockerfiles started separately, Tomcat and PostgreSQL belong to two distinct images and I think this is a very positive thing.
I really like to keep Dockerfiles in separate folders so I use this docker-compose.yaml:

version: '3.7'

services:
  tomcat_eb:
    build: ./tomcat
    image: tomcat-eb:v.9.0.17
    container_name: tomcat-eb-container
    ports:
      - 8888:8080
    restart: on-failure
    depends_on:
      - postgresql
    networks:
      - eb

  postgresql:
    build: ./postgresql-postgis
    image: tomcat-postgresql-postgis:v.9.0.17-9.6-2.4
    container_name: postgresql-postgis-container
    ports:
      - 5432:5432
    volumes:
      - pg_data:/var/lib/postgresql
    environment:
      POSTGRES_USER: "eb"
      POSTGRES_PASS: "password"
      POSTGRES_DBNAME: "gis"
      ALLOW_IP_RANGE: "0.0.0.0/0"
    restart: always
    networks:
      - eb

volumes:
  pg_data:

networks:
  eb:

Yes, I agree, keeping them in two separate folders is a cleaner solution.

It looks like your first error was from copy and pasting bad characters from the HTML page. Typing them over should clear it up. At least now you have an example to work from. I always prefer sample code to documentation myself. :wink:

~jr

Thank you very much John Rofrano, :star_struck:
I solved by simply choosing the following encoding on Notepad ++:
“UTF-8 encoding”
Before I used “Encoding in UTF-8-BOM”.
Running the DockerCompose command I read this:
"ERROR: Version in" .ser-compose.yaml "is unsupported. You might be seeing this error because you're using the wrong Compose file version. Either specify a supported version (eg" 2.2 "or" 3.3 ") and place your service definitions under theserviceskey, or omit the versionkey and place your service definitions at the root of the file to use version 1. "
So I edited your file by writing “version: ‘3.3’”.
After all this work DockerCompose started without problems.
I also had to type this:
docker-compose up --build
The only thing I failed to do is change the Dockerfile link.
If the Dockerfile is here:
“… \ Docker-Tomcat-PosgreSQL \ tomcat”
while the .war file is here:
“… \ Docker-Tomcat-PosgreSQL \ Application”
What should I edit in this line?
“… \ Docker-Tomcat-PosgreSQL \ tomcat \ Dockerfile”
“COPY ./*.war /usr/local/tomcat/webapps/ROOT.war”

If I have applications that can live outside of ROOT and I want to load them all on the server at the same time, can I do this with Docker? What should I write in the Dockerfile?

Thanks for sharing this code with you, this solution works in my project called mykfcexperience.

John Rofrano is a true Docker expert. I’m really happy with his code.
The following code does not work:

COPY ./../applicazioni/*.war /usr/local/tomcat/webapps/

I solved it by writing the code you find below:

COPY ./*.war /usr/local/tomcat/webapps/

I also put the files in “tomcat” instead of “applicazioni”.
But I would have preferred to use the “applicazioni” folder. Who knows what’s wrong.
Is it mandatory that the .war files and the Dockerfiles live in the same folder “tomcat”?

Rofrano why don’t you answer my questions anymore?

1 - Why the first script works while the second doesn’t? Two scripts are identical!!!

First script

version: '3.3'

services:
  tomcat_eb:
    build: ./tomcat
    image: tomcat-eb:v.9.0.17
    container_name: tomcat-eb-container
    ports:
      - 8888:8080
    restart: on-failure
    depends_on:
      - postgresql
    networks:
      - eb

  postgresql:
    build: ./postgresql-postgis
    image: tomcat-postgresql-postgis:v.9.0.17-9.6-2.4
    container_name: postgresql-postgis-container
    ports:
      - 5432:5432
    volumes:
      - pg_data:/var/lib/postgresql
    environment:
      POSTGRES_USER: "eb"
      POSTGRES_PASS: "password"
      POSTGRES_DBNAME: "gis"
      ALLOW_IP_RANGE: "0.0.0.0/0"
    restart: always
    networks:
      - eb

volumes:
  pg_data:

networks:
  eb:

Second script

version: '3.3'

services:
 tomcat_eb:
  build: ./tomcat
  image: tomcat-eb:v.9.0.17
  container_name: tomcat-eb-container
  ports:
   - 8888:8080
  restart: on-failure
  depends_on:
   - postgresql
  networks:
   - eb

 postgresql:
  build: ./postgresql-postgis
  image: tomcat-postgresql-postgis:v.9.0.17-9.6-2.4
  container_name: postgresql-postgis-container
  ports:
   - 5432:5432
  volumes:
   - pg_data: /var/lib/postgresql
  environment:
   POSTGRES_USER: "eb"
   POSTGRES_PASS: "password"
   POSTGRES_DBNAME: "gis"
   ALLOW_IP_RANGE: "0.0.0.0/0"
  restart: always
  networks:
   - eb

volume:
 pg_data:

networks:
 eb:

ERROR: The Compose file ‘.\docker-compose.yaml’ is invalid because:
Invalid top-level property “volume”. Valid top-level sections for this Compose file are: version, services, networks, volumes, secrets, configs, and extensions starting with “x-”.

You might be seeing this error because you’re using the wrong Compose file version. Either specify a supported version (e.g “2.2” or “3.3”) and place your service definitions under the services key, or omit the version key and place your service definitions at the root of the file to use version 1.
For more on the Compose file format versions, see https://docs.docker.com/compose/compose-file/
services.postgresql.volumes ‘type’ is a required property

2 - Why does Docker never work with Edge and IE?
3 - Why can’t I use “/…/” in Docker? What do you use to get around?
COPY ./../applicazioni/*.war /usr/local/tomcat/webapps/

Thank you

DOWNLOAD: https://gofile.io/?c=9CAKAK

Sorry, I didn’t see this sooner. I was on vacation in Italy. :wink:

They are not identical and the error message is telling you what is wrong. You used the word volume: and the correct syntax is volumes: (with an "s" at the end.

I can’t say since I use a Mac and you couldn’t pay me enough to use Windows.

For security reasons Docker will only pull resources from the folder that the Dockerfile is in and below it (known as the “build context”). So the COPY command requires that the source files are located within the current directory or some sub-directory.

If your application is following proper 12-factor design, it should be contained within a single git repo and if you place your Dockerfile in the root of that repo, everything will build correctly. You want the Dockerfile that builds the image for your war file to be in the same repo with the source that creates the war file. This way it won’t have to pull from outside that folder.

~jr

1 Like

I’m sorry, I didn’t know you were on vacation! You came to my country to vacation, very good! :slight_smile:
You’re right, the files are different. I’m really electrocuted.
I love Windows because it works great and above all it’s very cheap. I bought a notebook with Ryzen 2200U, 15.6, full HD monitor, 8GB of RAM and 256GB of SSD with 370 euros.
I can’t buy Apple because it costs too much but I’m convinced that it works well.
Apple’s design is unsurpassed.
Ok your script works perfect and it’s also understandable.
There’s one thing I didn’t understand:
If I enter this code:

docker rmi tomcat-postgresql-postgis:v.9.0.17-9.6-2.4
docker rmi tomcat-eb:v.9.0.17

I can’t reset the contents of the DBMS. This happens even without the use of DockerCompose.
If I enter the virtual Linux system on VirtualBox and type:
cd /var/lib/
I can’t find the postgresql file.
So where is the database saved?
The images “tomcat” and “kartoza / postgis” that I don’t delete contain the database?
It’s all very strange to me, I need clarification.
thank you

I didn’t realize that you lived in Italy. I was in Milan. Just before going on vacation, I gave a 3 hour hands-on tutorial on DevOps and Docker at the Universita’ Degli Studi Di Milano for the IEEE Services 2019 conference. Here is a description of my session:

https://conferences.computer.org/services/2019/tutorials/devops_tutorial.html

anyway…

This is a great question. In your docker-compose.yaml file you specified that you wanted Docker to create and manage a volume for you with the following lines of code:

volumes:
  pg_data:

Then you mapped that volume to the location inside of the PostgreSQL container where it looks for it’s database with these lines of code:

    volumes:
      - pg_data:/var/lib/postgresql

When you destroy a container with docker rm <container_name> or even remove the image with:

docker rmi tomcat-postgresql-postgis:v.9.0.17-9.6-2.4
docker rmi tomcat-eb:v.9.0.17

You are not affecting the volume pg_data at all. Docker is keeping that safe for you. This is why deleting containers and images doesn’t reset the database data.

So where is the database saved?

It is saved in a volume and you can see all of the volumes that Docker is managing for you with the command:

docker volume ls

At a minimum you should see:

$ docker volume ls
DRIVER              VOLUME NAME
local               pg_data

If you want to see where pg_data is located, you can use the inspect command like this:

$ docker volume inspect pg_data
[
    {
        "CreatedAt": "2019-04-10T10:07:24Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/pg_data/_data",
        "Name": "pg_data",
        "Options": null,
        "Scope": "local"
    }
]

From this you can see that the actual data is kept inside the VM that hosts Docker at:

/var/lib/docker/volumes/pg_data/_data

If you want to reset the database, all you need to do is delete this volume and it will be recreated the next time you run docker-compose.

The command to delete the volume is:

docker volume rm pg_data

That was a very long answer but I wanted you to understand how and why it works the way it does. Hopefully that helps clarify what is going on. If not, ask more questions. :wink:

~jr

1 Like

Thank you very much, everything is very clear.
So you are a super expert in the field.

Sorry, I noticed a malfunction.
After a few days if I go to see my volumes, I see that they are many and above all they don’t have the name I chose.
To delete them I have to use this code:

docker volume prune -f

This code does not work:

docker volume rm pg_data

Why does this happen, where am I wrong?
I want to use this code:

docker volume rm pg_data

:frowning:

docker volume ls
DRIVER VOLUME NAME
local 374717f09e118c9fcf54c79dd3b1e32dff96c96d3036294c3c7074ac83d65617
local 4beb3de74d406f3f0a9e21b00169ee3815a342c08932df3f9003ee4f831ac3a1
local 4dd868488ec5392a4a7af7bc2b84d6208e8f1479edc136c7da05115678573dc7

local 6bc90baa935ddd5236a6519f7e792b7501f7882b212a10cd46fc73783b960a2a
local dockertomcatposgresql_pg_data

Dockerfile:

VOLUME create pg_data

docker-compose.yaml:

- pg_data:/var/lib/postgresql

NOTE: This string is missing the “-”:
dockertomcatposgresql_pg_data
Can the “-” be used?

Ubuntu 18.04:

docker volume inspect pg_data
[]
Error: No such volume: pg_data

docker network ls
NETWORK ID          NAME                         DRIVER              SCOPE
c02582c6b967        03dockertomcatposgresql_eb   bridge              local
ee5adcaeb8c6        bridge                       bridge              local
4288207bc650        host                         host                local
09b5e51dc601        none                         null                local

Windows 10:

docker volume inspect pg_data
[]
Error: No such volume: pg_data

docker network ls
NETWORK ID          NAME                       DRIVER              SCOPE
5dff3ac1fa00        bridge                     bridge              local
360d1e5b22cf        dockertomcatposgresql_eb   bridge              local
76aabefdadf9        host                       host                local
6898337a5757        none                       null                local

I found another problem. If I run this file on Ubuntu my application can’t connect. On Windows I don’t have problems. Using JDBC with Ubuntu I use these credentials:

{
	"url": "jdbc:postgresql://localhost:5432/gis",
	"user": "eb",
	"password": "password"
}

On Windows I use these other credentials:

{
	"url": "jdbc:postgresql://192.168.99.103:5432/gis",
	"user": "eb",
	"password": "password"
}

prompt-windows.txt (3.8 KB)

docker-compose.txt (725 Bytes)


I have investigated the problem and I think it is a network problem but finding the solution is impossible for me.
My webapp crashes here:

conn = DriverManager.getConnection(url, user, password);

The parameters supplied to “DriverManager.getConnection()” are correct. I get “500 Internal Server Error” on Ubuntu while on Windows no.

url = "jdbc:postgresql://localhost:5432/gis";
user = "eb";
password = "password";

I also tried disabling the firewall on Ubuntu but I didn’t fix it. This is my DockerCompose installation:

sudo apt-get clean
sudo apt-get update
sudo apt-get dist-upgrade -y
sudo apt-get autoremove -y
sudo apt-get remove docker docker-engine docker.io containerd runc
sudo apt-get update
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
lsb_release -cs
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
bionic \
stable"
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
sudo docker run hello-world
sudo groupadd docker
sudo usermod -aG docker gi
sudo reboot
newgrp docker
docker run hello-world
sudo systemctl enable docker
sudo snap install docker
sudo apt  install docker-compose

docker-compose.yaml

version: '3.3'

services:
  tomcat_eb:
    build: ./tomcat
    image: image-tomcat-eb:v.1.0
    container_name: container-tomcat-eb
    ports:
      - 8888:8080
    restart: on-failure
    depends_on:
      - postgresql
    networks:
      - eb

  postgresql:
    build: ./postgresql-postgis
    image: image-postgresql-postgis-eb:v.1.0
    container_name: container-postgresql-postgis-eb
    ports:
      - 5432:5432
    volumes:
      - pg_data:/var/lib/postgresql
    environment:
      POSTGRES_USER: "eb"
      POSTGRES_PASS: "password"
      POSTGRES_DBNAME: "gis"
      ALLOW_IP_RANGE: "0.0.0.0/0"
    restart: always
    networks:
      - eb

volumes:
  pg_data:

networks:
  eb:

Tomcat Dockerfile:

FROM tomcat:9.0.22-jdk13-openjdk-oracle
LABEL Author="Nome Cognome"
EXPOSE 8080
COPY ./*.war /usr/local/tomcat/webapps/
CMD ["catalina.sh", "run"]

DBMS Dockerfile:

FROM kartoza/postgis:9.6-2.4
LABEL Author="Nome Cognome"
EXPOSE 5432
VOLUME create pg_data

Another thing I don’t understand is because I can’t use version 3.7, the one I think you’re using.

My apologies. I didn’t take into account the fact that you are using docker-compose and docker-compose prefixes the volume and network names with the project name. If you don’t specify a project name with the -p option, it uses the name of the folder that the docker-compose.yaml file is in followed by an underscore _. This is why your volume is named dockertomcatposgresql_pg_data instead if just pg_data.

To delete that volume, you need to use:

docker volume rm dockertomcatposgresql_pg_data

If you want to control the entire volume name, you can pass a project name to docker-compose like this:

docker-compose -p tomcat_eb up -d

This will name the volume tomcat_eb_pg_data instead.

Your problem here is with the use of localhost. PostgreSQL is not running on the localhost in your Tomcat container. It is running in its own container. You need to use the name of the service that you gave it in your docker-compose.yaml file instead.

It looks like in your docker-compose.yamlyou called it postgresql so your credentials should be:

{
	"url": "jdbc:postgresql://postgresql:5432/gis",
	"user": "eb",
	"password": "password"
}

Also, you should be passing this information to your Tomcat application as environment variables in your docker-compose.yaml file following 12-factor principals. Something like:

version: '3.3'

services:
  tomcat_eb:
    build: ./tomcat
    image: image-tomcat-eb:v.1.0
    container_name: container-tomcat-eb
    ports:
      - 8888:8080
    environment:
      DB_URL: "jdbc:postgresql://postgresql:5432/gis"
      DB_USER: "eb"
      DB_PASS: "password"
    restart: on-failure
    depends_on:
      - postgresql
    networks:
      - eb

  postgresql:
    build: ./postgresql-postgis
    image: image-postgresql-postgis-eb:v.1.0
    container_name: container-postgresql-postgis-eb
    ports:
      - 5432:5432
    volumes:
      - pg_data:/var/lib/postgresql
    environment:
      POSTGRES_USER: "eb"
      POSTGRES_PASS: "password"
      POSTGRES_DBNAME: "gis"
      ALLOW_IP_RANGE: "0.0.0.0/0"
    restart: always
    networks:
      - eb

volumes:
  pg_data:

networks:
  eb:

This will work the same in every environment (Windows or Ubuntu).

~jr