From installation to Enterprise Architecture: The complete guide.
Before writing Compose files, you need the engine running. Here are the commands to install Docker on a fresh Ubuntu 22.04/24.04 server.
# 1. Update and install dependencies
sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
# 2. Add Docker GPG Key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 3. Add Docker Repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 4. Install Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
# 5. Add user to docker group (No more 'sudo' required)
sudo usermod -aG docker ${USER}
# Note: You must logout and login again for step 5 to take effect!
This is the bare minimum required to get services running. It creates containers but lacks persistence and networking configuration.
version: '3.8'
services:
frontendjenkins:
image: jenkins/jenkins
ports:
- "8080:8080"
qaserver:
image: tomee
ports:
- "7070:8080"
depends_on:
- frontendjenkins
In this basic setup, Docker creates ephemeral containers. This means that while the application runs perfectly for a quick demo, it is catastrophic for production. When you stop the frontendjenkins container, the underlying file system is destroyed. All your build history, user accounts, and plugin configurations vanish instantly. Furthermore, because we haven't defined a custom network, these containers run on the default "Bridge" network, where DNS resolution is limited.
Here we introduce stability. We add Volumes for data persistence and Custom Networks for secure communication.
services:
jenkins:
container_name: jenkins
volumes:
- jenkins_home:/var/jenkins_home
networks:
- devnet
volumes:
jenkins_home:
networks:
devnet:
driver: bridge
By introducing a custom user-defined bridge network (`devnet`), we unlock Docker's internal DNS resolution. Now, the Jenkins container can ping the QA server simply by using the hostname `qaserver`. We don't need to hardcode IP addresses, which change every time a container restarts. Additionally, the Named Volume (`jenkins_home`) is now decoupled from the container lifecycle. Even if you delete the container entirely, your data persists in `/var/lib/docker/volumes/`, ready to be reattached.
The final evolution. We integrate PostgreSQL, add Healthchecks, and attach a full Monitoring Stack.
version: '3.8'
services:
# --- CI/CD & App Services ---
jenkins:
image: jenkins/jenkins:lts
ports: ["8080:8080", "50000:50000"]
volumes: [ "jenkins_home:/var/jenkins_home" ]
networks: [ "devnet" ]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
retries: 5
qaserver:
image: tomee:latest
depends_on:
jenkins:
condition: service_healthy
networks: [ "devnet" ]
environment:
- APP_ENV=qa
- DB_HOST=postgres_db
# --- Database ---
db:
image: postgres:15
container_name: postgres_db
environment:
- POSTGRES_DB=companydb
volumes: [ "db_data:/var/lib/postgresql/data" ]
networks: [ "devnet" ]
# --- Monitoring ---
prometheus:
image: prom/prometheus:latest
ports: [ "9090:9090" ]
networks: [ "devnet" ]
grafana:
image: grafana/grafana:latest
ports: [ "3000:3000" ]
depends_on: [ "prometheus" ]
networks: [ "devnet" ]
volumes:
jenkins_home:
db_data:
networks:
devnet:
driver: bridge
One of the most common failures in CI/CD stacks is the "Race Condition." Usually, a database takes 10–15 seconds to initialize, but the application tries to connect in 2 seconds. The app crashes, restarts, and crashes again. In this setup, we use depends_on: condition: service_healthy. The QA Server will strictly wait until Jenkins reports a "Healthy" status via its internal curl check before it even attempts to start.
A quick reference for the single-line commands you will use daily.
| Command | Description |
|---|---|
docker ps -a |
List running and stopped containers. |
docker images |
List all downloaded images. |
docker logs -f [id] |
View live logs of a container. |
docker exec -it [id] bash |
Go inside a running container (shell). |
docker system prune -a |
DANGER: Deletes all stopped containers, unused networks, and images. |
docker-compose up -d --build |
Build and start containers in the background. |