Build a single image based on docker compose containers - docker

My compose-yaml has 3 services
I am able to run the containers sucessfully when i am using docker-compose up.
Now i want to build these 3 containers into single image. Is it possible?
here is my
compose-yaml
version: '2'
services:
tomcat:
container_name: tomcatcomposejdk
build: .
image: 'apexits/ubuntu-oracle-jdk8-tomcat9'
ports:
- "8787:8080"
- "5003:5003"
networks:
b:
ipv4_address: 10.5.0.6
expose:
- "8787"
- "5003"
mysql:
container_name: mysqlcompose
build: .
image: 'mysql:5.6.36'
ports:
- "3306:3306"
expose:
- "3306"
networks:
b:
ipv4_address: 10.5.0.7
environment:
MYSQL_DATABASE: "bird251"
MYSQL_ROOT_PASSWORD: "root"
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
volumes:
- ./BIRD251.sql:/tmp/BIRD251.sql
- ./import.sh:/tmp/import.sh
elasticsearch:
container_name: escompose
build: .
image: 'elasticsearch:2.3.4'
ports:
- "9200:9200"
- "9300:9300"
expose:
- "9200"
- "9300"
networks:
b:
ipv4_address: 10.5.0.8
networks:
b:
driver: bridge
ipam:
config:
- subnet: 10.5.0.0/16
gateway: 10.5.0.1

This is not recommended at all. You will need to reverse engineer each image and copy the needed binaries/files into the combined image. The approach for that is to use docker multistage build:
FROM apexits/ubuntu-oracle-jdk8-tomcat9 as tomcat
FROM mysql:5.6.36 as mysql
FROM elasticsearch:2.3.4
COPY --from=tomcat /.../tomcat-installtion .../tomcat-installation
COPY --from=mysql /.../mysql-installtion .../mysql-installation
...
This approach is very trick and you need to reverse engineer each image to figure out which files/folder/config need to be copied onto the combined image...
Alternatively, you can start from one of the images and install the other programs using standard installation guidelines for each.
Even if you are successful with that, you will need to start multiple processes in same container which is not recommended and will introduce many complexities.

Related

How to extend Dockerimages via docker-compose

i try to extend my Basic Images from Webdevops.
I'll try to add the base-app to my Container that already exists.
Thats my docker-compose:
version: "3"
services:
base-app:
image: "webdevops/base-app"
restart: always
apache:
image: "webdevops/php-apache-dev:7.2"
container_name: apache
restart: always
ports:
- '80:80'
- '443:443'
depends_on:
- mysql
- base-app
volumes:
- "./:/app"
environment:
- XDEBUG_MODE=develop,debug
- XDEBUG_CLIENT_HOST=host.docker.internal
- XDEBUG_CLIENT_PORT=9003 # 9000=xdebug v2, 9003=v3
- XDEBUG_REMOTE_CONNECT_BACK=0
- XDEBUG_REMOTE_AUTOSTART=1
- XDEBUG_IDE_KEY=docker
- XDEBUG_START_WITH_REQUEST=trigger
extra_hosts:
- "host.docker.internal:host-gateway"
mysql:
image: "mysql:latest"
restart: always
container_name: mysql
ports:
- '3306:3306'
volumes:
- './mysql:/var/lib/mysql'
depends_on:
- base-app
environment:
MYSQL_ROOT_PASSWORD: 'xxxxx'
How to extend my Images with base-app?
You can extend any image using a Dockerfile. For example, you might write a Dockerfile
FROM webdevops/php-apache-dev:7.2
COPY . /app
You can do other steps as required, like RUNning an installation command or setting an alternate CMD you need this image to run. You generally should avoid putting host names or credentials of any sort into the Docker image, leave these as environment: settings in the Compose file.
In your docker-compose.yml file, use a build: block to indicate this image should be built. Do not include an image: line; unless you're specifically planning to push this extended image to a registry; and if you do it must have a different name from the base image.
services:
apache:
build: . # _instead of_ image:
restart: always
depends_on: [...]
ports: [...]
environment: [...]
# no volumes: since the code is already in the image
# container_name: is usually unnecessary

docker-compose force services to create seperate containers even when images are the same

I have 2 services which use the same image:, what can i do, to force docker-compose to generate 2 seperate containers?
Thanks!
EDIT:
Full docker-compose:
version: "3.5"
services:
database:
container_name: proj-database
env_file: ../orm/.env.${PROJ_ENV}
image: postgres
restart: always
ports:
- 5432:5432
networks:
- proj
api:
image: golang:1.17
container_name: proj-api
env_file: ../cryptoModuleAPI/.env.${PROJ_ENV}
restart: always
build: ../cryptoModuleAPI/
links:
- database:database
ports:
- 8080:8080
volumes:
- ../cryptoModuleAPI:/proj/api
- ../orm:/proj/orm
networks:
- proj
admin:
image: golang:1.17
container_name: proj-admin
env_file: ../admin/.env.${PROJ_ENV}
restart: always
build: ../admin/
links:
- database:database
ports:
- 8081:8081
volumes:
- ../admin:/proj/admin
- ../orm:/proj/orm
networks:
- proj
networks:
proj:
external:
name: proj
I just run with docker-compose up
You misunderstand how the build and image directives work when used together.
Paraphrasing the docs,
https://docs.docker.com/compose/compose-file/compose-file-v3/#build
If you specify image as well as build, then Compose names the built image with the value of the image directive.
Compose is going to build two images, both named the same thing. Only one will survive. I'm surprised your app spins up at all!
Provide a different name for the image directive of each service, or leave it out entirely.

Connect to database from another container

Please help me if it's possible.
I need to start 2 applications with a single database.
I have 2 applications. First domain.com, 2-nd api.domain.com. Each application has docker-compose.yaml files.
domain.com - CMS
version: "3.8"
services:
web:
container_name: domain_web
build:
context: ./docker/php
dockerfile: Dockerfile
working_dir: /var/www/html
#command: composer install
volumes:
- ./:/var/www/html
- ./docker/php/app.conf:/etc/apache2/sites-available/000-default.conf
- ./docker/php/hosts:/etc/hosts
networks:
domain:
ipv4_address: 10.9.0.5
networks:
domain:
driver: bridge
ipam:
config:
- subnet: 10.9.0.0/16
gateway: 10.9.
volumes:
bel_baza:
api.domain.com - Laravel 5.6
version: "3.8"
services:
web:
container_name: api_domain_web
build:
context: ./docker/php
dockerfile: Dockerfile
working_dir: /var/www/html
# command: composer install
volumes:
- ./:/var/www/html
- ./docker/php/app.conf:/etc/apache2/sites-available/000-default.conf
- ./docker/php/hosts:/etc/hosts
networks:
api_domain:
ipv4_address: 10.15.0.5
db:
image: mysql:5.7
command: --default-authentication-plugin=mysql_native_password
restart: always
container_name: api_domain_db
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: domain
MYSQL_USER: user
MYSQL_PASSWORD: user
volumes:
- api_domain_baza:/var/lib/mysql
- ./docker/db:/docker-entrypoint-initdb.d
networks:
api_domain:
ipv4_address: 10.15.0.6
phpmyadmin:
image: phpmyadmin
restart: always
container_name: api_domain_pma
networks:
api_domain:
ipv4_address: 10.15.0.7
redis:
image: redis:3.0
container_name: api_domain_redis
networks:
api_domain:
ipv4_address: 10.15.0.10
networks:
api_domain:
driver: bridge
ipam:
config:
- subnet: 10.15.0.0/16
gateway: 10.15.0.1
volumes:
api_domain_baza:
api_domain started successfully.
I need to connect domain.com with database api_domain_db. For connecting host, I used IP address 10.15.0.6. First application not connected to the database from 2nd application.
What is my problem?
How I can connect domain.com with the database of 2nd application?
your problem is your are using separate docker compose applications for each application. And by default those applications can not access each other inner parts:
By default Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.
doc is here - https://docs.docker.com/compose/networking/
So it is like it creates separate network for each docker compose.
if you want them both to see each other inner part you can create external docker network as this:
docker network create --subnet 10.1.0.0/24 network_name
and then use that network in both docker compose like this:
networks:
default:
external:
name: network_name
services:
.....
if you need fixed IPs, you can define them as
app:
image: ...
networks:
default:
ipv4_address: 10.1.0.10

best practice for sshfs via docker-compose to other computer but don't want to expose port publicly

I want to mount a volume in docker via sshfs to another computer that's ideally on my local network that my docker host is on. The problem is that it can't see the host if I try to ssh into via the usual 192.168.. ip. The other option I have is to expose the machines SSH port to the internet, but I know that is bad practice, so i'm wondering if there's any other way to do this? Can I connect via a VPN of some sort or can I make the docker volume reach my local network on my host?
Ideally i'm just looking for some guidance.
version: "3"
volumes:
local_postgres_data: {}
local_postgres_data_backups: {}
sshfs:
driver: vieux/sshfs:latest
driver_opts:
sshcmd: "secretuser#192.168.0.114:/home"
password: "secretpassword"
allow_other: ""
services:
nginx:
image: nginx:alpine
container_name: nx01
ports:
- "80:8000"
- "443:443"
volumes:
- ./src:/src
- ./config/nginx:/etc/nginx/conf.d
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
depends_on:
- web
frontend:
container_name: frontend-vue
build:
context: .
dockerfile: compose/frontend/Dockerfile
volumes:
- './frontend:/frontend'
- '/frontend/node_modules'
ports:
- '8081:8080'
web:
build:
context: .
dockerfile: compose/django/Dockerfile
container_name: dx01
depends_on:
- db
- redis
volumes:
- ./src:/src
- sshfs:/src/mount
expose:
- "8000"
env_file:
- ./.envs/.django
db:
build:
context: .
dockerfile: compose/postgres/Dockerfile
container_name: px01
env_file:
- ./.envs/.postgres
volumes:
- local_postgres_data:/var/lib/postgresql/data
- local_postgres_data_backups:/backups
redis:
image: redis:latest
container_name: rs01
ports:
- "127.0.0.1:6379:6379"

Docker compose 3.1, communication between two docker-compose.yml

For past 3 days I have been trying to connect two docker containers generated by two separate docker-compose files.
I tried a lot of approaches none seem to be working. Currently after adding network to compose files, service with added network doesn't start. My goal is to access endpoint from another container.
Endpoint-API compose file:
version: "3.1"
networks:
test:
services:
mariadb:
image: mariadb:10.1
container_name: list-rest-api-mariadb
working_dir: /application
volumes:
- .:/application
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=list-api
- MYSQL_USER=list-api
- MYSQL_PASSWORD=root
ports:
- "8003:3306"
webserver:
image: nginx:stable
container_name: list-rest-api-webserver
working_dir: /application
volumes:
- .:/application
- ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "8005:80"
networks:
- test
php-fpm:
build: docker/php-fpm
container_name: list-rest-api-php-fpm
working_dir: /application
volumes:
- .:/application
- ./docker/php-fpm/php-ini-overrides.ini:/etc/php/7.2/fpm/conf.d/99-overrides.ini
Consumer compose file:
version: "3.1"
networks:
test:
services:
consumer-mariadb:
image: mariadb:10.1
container_name: consumer-service-mariadb
working_dir: /consumer
volumes:
- .:/consumer
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=consumer
- MYSQL_USER=consumer
- MYSQL_PASSWORD=root
ports:
- "8006:3306"
consumer-webserver:
image: nginx:stable
container_name: consumer-service-webserver
working_dir: /consumer
volumes:
- .:/consumer
- ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "8011:80"
networks:
- test
consumer-php-fpm:
build: docker/php-fpm
container_name: consumer-service-php-fpm
working_dir: /consumer
volumes:
- .:/consumer
- ./docker/php-fpm/php-ini-overrides.ini:/etc/php/7.2/fpm/conf.d/99-overrides.ini
Could someone tell me best way of accessing API container from within consumer? I'm loosing my mind on this one.
Your two
networks:
test:
don't refer to the same network, but they are independent and don't talk to each other.
What you could do is having an external and pre-existing network that both compose file can talk and share. You can do that with docker network create, and then refer to that in your compose files with
networks:
default:
external:
name: some-external-network-here

Resources