1. Persiapan dan Prerequisites
Instalasi Docker
Untuk Ubuntu/Debian:
# Update sistem
sudo apt update
# Install dependencies
sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
# Add Docker GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Add Docker repository
echo "deb [arch=amd64 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
# Install Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io
# Add user to docker group
sudo usermod -aG docker $USER
Untuk Windows/Mac:
- Download Docker Desktop dari https://www.docker.com/products/docker-desktop
- Install dan restart komputer
Verifikasi Instalasi
docker --version
docker run hello-world
2. Struktur Proyek PHP
Buat struktur folder proyek:
my-php-app/
├── src/
│ ├── index.php
│ ├── config/
│ │ └── database.php
│ └── pages/
│ └── about.php
├── Dockerfile
├── docker-compose.yml
├── nginx.conf
└── .dockerignore
File Aplikasi PHP
src/index.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My PHP Docker App</title>
<style>
body { font-family: Arial, sans-serif; margin: 50px; }
.container { max-width: 800px; margin: 0 auto; }
.info-box { background: #f4f4f4; padding: 20px; border-radius: 5px; }
</style>
</head>
<body>
<div class="container">
<h1>Selamat Datang di Aplikasi PHP Docker!</h1>
<div class="info-box">
<h2>Informasi Server</h2>
<p><strong>PHP Version:</strong> <?php echo phpversion(); ?></p>
<p><strong>Server:</strong> <?php echo $_SERVER['SERVER_SOFTWARE']; ?></p>
<p><strong>Document Root:</strong> <?php echo $_SERVER['DOCUMENT_ROOT']; ?></p>
<p><strong>Server Time:</strong> <?php echo date('Y-m-d H:i:s'); ?></p>
</div>
<h2>PHP Extensions</h2>
<div class="info-box">
<?php
$extensions = get_loaded_extensions();
sort($extensions);
foreach ($extensions as $ext) {
echo "<span style='display: inline-block; margin: 2px 5px; padding: 2px 8px; background: #007cba; color: white; border-radius: 3px; font-size: 12px;'>$ext</span>";
}
?>
</div>
<h2>Database Connection Test</h2>
<div class="info-box">
<?php
try {
$host = getenv('DB_HOST') ?: 'localhost';
$dbname = getenv('DB_NAME') ?: 'testdb';
$username = getenv('DB_USER') ?: 'root';
$password = getenv('DB_PASS') ?: '';
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
echo "<p style='color: green;'>✅ Database connection successful!</p>";
echo "<p>Host: $host | Database: $dbname</p>";
} catch (PDOException $e) {
echo "<p style='color: orange;'>⚠️ Database connection failed: " . $e->getMessage() . "</p>";
echo "<p>This is normal if database is not configured.</p>";
}
?>
</div>
<p><a href="pages/about.php">About Page</a></p>
</div>
</body>
</html>
src/pages/about.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>About - My PHP Docker App</title>
<style>
body { font-family: Arial, sans-serif; margin: 50px; }
.container { max-width: 800px; margin: 0 auto; }
</style>
</head>
<body>
<div class="container">
<h1>About This Application</h1>
<p>This is a sample PHP application running in Docker container.</p>
<p>Built with PHP <?php echo phpversion(); ?> and Nginx.</p>
<p><a href="../index.php">Back to Home</a></p>
</div>
</body>
</html>
src/config/database.php:
<?php
class Database {
private $host;
private $dbname;
private $username;
private $password;
private $pdo;
public function __construct() {
$this->host = getenv('DB_HOST') ?: 'localhost';
$this->dbname = getenv('DB_NAME') ?: 'testdb';
$this->username = getenv('DB_USER') ?: 'root';
$this->password = getenv('DB_PASS') ?: '';
}
public function connect() {
try {
$this->pdo = new PDO("mysql:host={$this->host};dbname={$this->dbname}",
$this->username, $this->password);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $this->pdo;
} catch (PDOException $e) {
throw new Exception("Connection failed: " . $e->getMessage());
}
}
}
?>
3. Dockerfile
Dockerfile:
# Menggunakan PHP 8.2 dengan Apache sebagai base image
FROM php:8.2-apache
# Set working directory
WORKDIR /var/www/html
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
libzip-dev \
zip \
unzip \
nginx \
supervisor \
&& rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-install \
pdo_mysql \
mbstring \
exif \
pcntl \
bcmath \
gd \
zip
# Enable Apache modules
RUN a2enmod rewrite ssl headers
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Copy custom Apache configuration
COPY apache-config.conf /etc/apache2/sites-available/000-default.conf
# Copy application files
COPY src/ /var/www/html/
# Set proper permissions
RUN chown -R www-data:www-data /var/www/html \
&& chmod -R 755 /var/www/html
# Expose port 80
EXPOSE 80
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
# Start Apache
CMD ["apache2-foreground"]
4. Konfigurasi Apache
apache-config.conf:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# Enable PHP
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
# Logging
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# Security headers
Header always set X-Content-Type-Options nosniff
Header always set X-Frame-Options DENY
Header always set X-XSS-Protection "1; mode=block"
</VirtualHost>
5. Docker Compose (Opsional)
docker-compose.yml:
version: '3.8'
services:
php-app:
build: .
container_name: my-php-app
ports:
- "8080:80"
volumes:
- ./src:/var/www/html
environment:
- DB_HOST=mysql
- DB_NAME=myapp
- DB_USER=root
- DB_PASS=rootpassword
depends_on:
- mysql
networks:
- app-network
mysql:
image: mysql:8.0
container_name: mysql-db
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppassword
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app-network
phpmyadmin:
image: phpmyadmin:latest
container_name: phpmyadmin
environment:
PMA_HOST: mysql
PMA_PORT: 3306
PMA_USER: root
PMA_PASSWORD: rootpassword
ports:
- "8081:80"
depends_on:
- mysql
networks:
- app-network
volumes:
mysql_data:
networks:
app-network:
driver: bridge
6. File Pendukung
.dockerignore:
.git
.gitignore
README.md
Dockerfile
docker-compose.yml
node_modules
*.log
.env.local
.env.*.local
init.sql:
CREATE DATABASE IF NOT EXISTS myapp;
USE myapp;
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users (name, email) VALUES
('John Doe', 'john@example.com'),
('Jane Smith', 'jane@example.com');
7. Build dan Menjalankan Docker Image
Method 1: Menggunakan Docker Commands
Build Image:
# Masuk ke direktori proyek
cd my-php-app
# Build Docker image
docker build -t my-php-app:latest .
# Lihat images yang tersedia
docker images
Menjalankan Container:
# Run container sederhana
docker run -d -p 8080:80 --name php-container my-php-app:latest
# Run dengan environment variables
docker run -d -p 8080:80 \
-e DB_HOST=localhost \
-e DB_NAME=myapp \
-e DB_USER=root \
-e DB_PASS=password \
--name php-container \
my-php-app:latest
# Run dengan volume mapping untuk development
docker run -d -p 8080:80 \
-v $(pwd)/src:/var/www/html \
--name php-container \
my-php-app:latest
Method 2: Menggunakan Docker Compose
# Build dan jalankan semua services
docker-compose up -d --build
# Lihat status containers
docker-compose ps
# Lihat logs
docker-compose logs -f php-app
# Stop semua services
docker-compose down
# Stop dan hapus volumes
docker-compose down -v
8. Management dan Monitoring
Perintah Docker Berguna
# Lihat containers yang berjalan
docker ps
# Lihat semua containers
docker ps -a
# Masuk ke container
docker exec -it php-container bash
# Lihat logs container
docker logs php-container
# Stop container
docker stop php-container
# Start container
docker start php-container
# Remove container
docker rm php-container
# Remove image
docker rmi my-php-app:latest
Monitoring Resource Usage
# Lihat resource usage
docker stats php-container
# Inspect container
docker inspect php-container
# Lihat port mapping
docker port php-container
9. Testing dan Debugging
Test Aplikasi
Setelah container berjalan, buka browser dan akses:
- Aplikasi utama: http://localhost:8080
- PhpMyAdmin: http://localhost:8081 (jika menggunakan docker-compose)
Debugging
# Check container logs
docker logs -f php-container
# Masuk ke container untuk debugging
docker exec -it php-container bash
# Check Apache error logs di dalam container
tail -f /var/log/apache2/error.log
# Check Apache access logs
tail -f /var/log/apache2/access.log
# Test PHP configuration
docker exec php-container php -v
docker exec php-container php -m
10. Production Considerations
Optimalisasi Image
Multi-stage Dockerfile untuk production:
# Build stage
FROM php:8.2-apache as builder
WORKDIR /var/www/html
COPY src/ .
RUN composer install --no-dev --optimize-autoloader
# Production stage
FROM php:8.2-apache
WORKDIR /var/www/html
# Install hanya dependencies yang diperlukan
RUN apt-get update && apt-get install -y \
libpng-dev \
libzip-dev \
&& docker-php-ext-install pdo_mysql gd zip \
&& rm -rf /var/lib/apt/lists/*
# Copy dari build stage
COPY --from=builder /var/www/html /var/www/html
COPY apache-config.conf /etc/apache2/sites-available/000-default.conf
RUN a2enmod rewrite \
&& chown -R www-data:www-data /var/www/html
EXPOSE 80
CMD ["apache2-foreground"]
Security Best Practices
# Jangan run sebagai root
RUN groupadd -r phpuser && useradd -r -g phpuser phpuser
USER phpuser
# Set proper file permissions
RUN chmod -R 644 /var/www/html \
&& find /var/www/html -type d -exec chmod 755 {} \;
# Remove unnecessary packages
RUN apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false
Environment Variables untuk Production
# Production environment
docker run -d -p 80:80 \
-e ENVIRONMENT=production \
-e DB_HOST=prod-db-server \
-e DB_NAME=prod_database \
-e DB_USER=prod_user \
-e DB_PASS=secure_password \
--restart=unless-stopped \
--name php-prod \
my-php-app:latest
11. Troubleshooting
Masalah Umum dan Solusi
1. Port sudah digunakan:
# Cek port yang digunakan
netstat -tulpn | grep :8080
# Gunakan port lain
docker run -d -p 8090:80 --name php-container my-php-app:latest
2. Permission denied:
# Fix ownership
sudo chown -R $USER:$USER ./src
chmod -R 755 ./src
3. Container tidak bisa diakses:
# Check firewall
sudo ufw allow 8080
# Check container status
docker ps
docker logs php-container
4. Database connection error:
# Check network connection
docker network ls
docker network inspect bridge
# Test database connectivity
docker exec php-container ping mysql
Kesimpulan
Tutorial ini memberikan panduan lengkap untuk membuat, build, dan menjalankan aplikasi PHP dalam Docker container. Dengan mengikuti langkah-langkah di atas, Anda dapat:
- Membuat Docker image untuk aplikasi PHP
- Mengkonfigurasi Apache dan PHP extensions
- Mengelola container dengan Docker dan Docker Compose
- Melakukan debugging dan monitoring
- Mengoptimalkan untuk production
Docker memberikan fleksibilitas untuk mengembangkan dan deploy aplikasi PHP dengan konsistensi lingkungan yang terjamin.