first commit
This commit is contained in:
95
docker/entrypoint.sh
Normal file
95
docker/entrypoint.sh
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# MBIP Pusat Data — Container Entrypoint
|
||||
# Dijalankan setiap kali container bermula sebelum PHP-FPM boot
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
DB_HOST="${DB_HOST:-host.docker.internal}"
|
||||
DB_PORT="${DB_PORT:-3306}"
|
||||
DB_USER="${DB_USERNAME:-root}"
|
||||
DB_PASS="${DB_PASSWORD}"
|
||||
TIMEOUT=60
|
||||
|
||||
echo "[entrypoint] Memulakan MBIP Pusat Data — PHP $(php -r 'echo PHP_VERSION;')"
|
||||
echo "[entrypoint] MySQL luaran: ${DB_HOST}:${DB_PORT}"
|
||||
|
||||
# ── 1. Tunggu MySQL luaran sedia ─────────────────────────────
|
||||
echo "[entrypoint] Menunggu MySQL..."
|
||||
elapsed=0
|
||||
until mysqladmin ping -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" -p"${DB_PASS}" \
|
||||
--connect-timeout=3 --silent 2>/dev/null; do
|
||||
if [ "$elapsed" -ge "$TIMEOUT" ]; then
|
||||
echo "[entrypoint] RALAT: MySQL di ${DB_HOST}:${DB_PORT} tidak bertindak balas dalam ${TIMEOUT}s. Dibatalkan."
|
||||
exit 1
|
||||
fi
|
||||
echo "[entrypoint] MySQL belum sedia — cuba lagi dalam 3s... (${elapsed}s berlalu)"
|
||||
sleep 3
|
||||
elapsed=$((elapsed + 3))
|
||||
done
|
||||
echo "[entrypoint] MySQL sedia."
|
||||
|
||||
# ── 2. Pasang composer dependencies jika vendor tiada ────────
|
||||
if [ ! -f /var/www/html/vendor/autoload.php ]; then
|
||||
echo "[entrypoint] vendor/ tidak dijumpai — menjalankan composer install..."
|
||||
composer install --no-dev --no-interaction --no-progress --optimize-autoloader --no-scripts \
|
||||
--working-dir=/var/www/html
|
||||
fi
|
||||
|
||||
# ── 3. Pastikan direktori storage wujud ──────────────────────
|
||||
mkdir -p \
|
||||
/var/www/html/storage/app/public \
|
||||
/var/www/html/storage/app/private/reports \
|
||||
/var/www/html/storage/framework/cache/data \
|
||||
/var/www/html/storage/framework/sessions \
|
||||
/var/www/html/storage/framework/testing \
|
||||
/var/www/html/storage/framework/views \
|
||||
/var/www/html/storage/logs \
|
||||
/var/log/php-fpm \
|
||||
/var/log/supervisor
|
||||
|
||||
chown -R www-data:www-data /var/www/html/storage
|
||||
chmod -R 775 /var/www/html/storage
|
||||
|
||||
# ── 4. Bersihkan bootstrap cache lapuk ───────────────────────
|
||||
rm -f /var/www/html/bootstrap/cache/*.php
|
||||
mkdir -p /var/www/html/bootstrap/cache
|
||||
chown -R www-data:www-data /var/www/html/bootstrap/cache
|
||||
|
||||
# ── 5. Jana APP_KEY jika belum ditetapkan ────────────────────
|
||||
if [ -z "${APP_KEY}" ]; then
|
||||
echo "[entrypoint] APP_KEY belum ditetapkan — menjana..."
|
||||
php artisan key:generate --force
|
||||
fi
|
||||
|
||||
# ── 6. Cipta storage symlink ─────────────────────────────────
|
||||
if [ ! -L /var/www/html/public/storage ]; then
|
||||
echo "[entrypoint] Mencipta storage symlink..."
|
||||
php artisan storage:link --force
|
||||
fi
|
||||
|
||||
# ── 7. Jalankan migrasi pangkalan data ───────────────────────
|
||||
echo "[entrypoint] Menjalankan migrasi..."
|
||||
php artisan migrate --force --no-interaction
|
||||
|
||||
# ── 8. Semai data jika kosong (kali pertama sahaja) ──────────
|
||||
ROLE_COUNT=$(php artisan tinker --execute="echo \Spatie\Permission\Models\Role::count();" 2>/dev/null | tail -1)
|
||||
if [ "${ROLE_COUNT}" = "0" ] || [ -z "${ROLE_COUNT}" ]; then
|
||||
echo "[entrypoint] Pangkalan data kosong — menjalankan seeder..."
|
||||
php artisan db:seed --force --no-interaction
|
||||
fi
|
||||
|
||||
# ── 9. Bina semula cache ─────────────────────────────────────
|
||||
echo "[entrypoint] Membina semula cache..."
|
||||
su -s /bin/sh www-data -c "php artisan package:discover --ansi"
|
||||
su -s /bin/sh www-data -c "php artisan optimize:clear"
|
||||
su -s /bin/sh www-data -c "php artisan config:cache"
|
||||
su -s /bin/sh www-data -c "php artisan route:cache"
|
||||
su -s /bin/sh www-data -c "php artisan view:cache"
|
||||
su -s /bin/sh www-data -c "php artisan event:cache"
|
||||
|
||||
echo "[entrypoint] Persediaan selesai. Memulakan PHP-FPM..."
|
||||
|
||||
# ── 10. Mulakan PHP-FPM + queue worker melalui Supervisor ────
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
78
docker/nginx/default.conf
Normal file
78
docker/nginx/default.conf
Normal file
@@ -0,0 +1,78 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name _;
|
||||
|
||||
root /var/www/html/public;
|
||||
index index.php;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
# ── Laravel health check ──────────────────────────────────
|
||||
location = /up {
|
||||
access_log off;
|
||||
fastcgi_pass app:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# ── Aset statik — cache jangka panjang ───────────────────
|
||||
location ~* \.(css|js|ico|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot|webp)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
access_log off;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# ── Fail awam (storage/app/public) ────────────────────────
|
||||
# Nota: laporan PDF disimpan di storage/app/private dan HANYA
|
||||
# boleh dimuat turun melalui laluan Laravel terlindung polisi.
|
||||
location /storage/ {
|
||||
alias /var/www/html/storage/app/public/;
|
||||
expires 30d;
|
||||
add_header Cache-Control "public";
|
||||
access_log off;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# ── Semua permintaan lain → Laravel ──────────────────────
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# ── PHP-FPM ───────────────────────────────────────────────
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass app:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||
fastcgi_param PHP_VALUE "upload_max_filesize=25M \n post_max_size=30M";
|
||||
include fastcgi_params;
|
||||
|
||||
fastcgi_connect_timeout 60s;
|
||||
fastcgi_send_timeout 300s;
|
||||
fastcgi_read_timeout 300s;
|
||||
|
||||
fastcgi_buffers 16 16k;
|
||||
fastcgi_buffer_size 32k;
|
||||
}
|
||||
|
||||
# ── Sekat fail tersembunyi/dot ────────────────────────────
|
||||
location ~ /\.(?!well-known).* {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# ── Sekat fail sensitif ───────────────────────────────────
|
||||
location ~* \.(env|log|git|gitignore|md|lock|json|yaml|yml)$ {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
error_page 404 /index.php;
|
||||
error_page 500 502 503 504 /index.php;
|
||||
}
|
||||
48
docker/nginx/nginx.conf
Normal file
48
docker/nginx/nginx.conf
Normal file
@@ -0,0 +1,48 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
server_tokens off;
|
||||
|
||||
client_max_body_size 30M;
|
||||
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_min_length 256;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/json
|
||||
application/xml
|
||||
image/svg+xml
|
||||
font/woff
|
||||
font/woff2;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
2
docker/php/opcache-dev.ini
Normal file
2
docker/php/opcache-dev.ini
Normal file
@@ -0,0 +1,2 @@
|
||||
opcache.enable = 0
|
||||
opcache.enable_cli = 0
|
||||
61
docker/php/php.ini
Normal file
61
docker/php/php.ini
Normal file
@@ -0,0 +1,61 @@
|
||||
; ─────────────────────────────────────────────────────────────
|
||||
; MBIP Pusat Data — PHP 8.4 Custom Configuration
|
||||
; Digunakan untuk CLI dan FPM
|
||||
; ─────────────────────────────────────────────────────────────
|
||||
|
||||
[PHP]
|
||||
; ── Zon masa ─────────────────────────────────────────────────
|
||||
date.timezone = Asia/Kuala_Lumpur
|
||||
|
||||
; ── Memori ───────────────────────────────────────────────────
|
||||
memory_limit = 256M
|
||||
max_execution_time = 300
|
||||
max_input_time = 300
|
||||
max_input_vars = 5000
|
||||
default_socket_timeout = 60
|
||||
|
||||
; ── Had muat naik (laporan PDF, maks ~20MB) ──────────────────
|
||||
file_uploads = On
|
||||
upload_max_filesize = 25M
|
||||
post_max_size = 30M
|
||||
max_file_uploads = 10
|
||||
|
||||
; ── Pelaporan ralat (produksi — log sahaja) ──────────────────
|
||||
display_errors = Off
|
||||
display_startup_errors = Off
|
||||
log_errors = On
|
||||
error_log = /var/www/html/storage/logs/php_errors.log
|
||||
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
|
||||
|
||||
; ── Keselamatan ──────────────────────────────────────────────
|
||||
expose_php = Off
|
||||
allow_url_fopen = Off
|
||||
allow_url_include = Off
|
||||
session.use_strict_mode = 1
|
||||
session.cookie_httponly = 1
|
||||
session.cookie_samesite = "Lax"
|
||||
|
||||
; ── Output buffering ─────────────────────────────────────────
|
||||
output_buffering = 4096
|
||||
|
||||
; ── OPcache ──────────────────────────────────────────────────
|
||||
[opcache]
|
||||
opcache.enable = 1
|
||||
opcache.enable_cli = 1
|
||||
opcache.memory_consumption = 128
|
||||
opcache.interned_strings_buffer = 16
|
||||
opcache.max_accelerated_files = 20000
|
||||
opcache.validate_timestamps = 1
|
||||
opcache.revalidate_freq = 0
|
||||
opcache.save_comments = 1
|
||||
opcache.fast_shutdown = 1
|
||||
opcache.jit_buffer_size = 64M
|
||||
opcache.jit = tracing
|
||||
|
||||
; ── Realpath cache ───────────────────────────────────────────
|
||||
realpath_cache_size = 4096K
|
||||
realpath_cache_ttl = 600
|
||||
|
||||
; ── MySQLi / PDO ─────────────────────────────────────────────
|
||||
[MySQLi]
|
||||
mysqli.default_port = 3306
|
||||
44
docker/php/www.conf
Normal file
44
docker/php/www.conf
Normal file
@@ -0,0 +1,44 @@
|
||||
; ─────────────────────────────────────────────────────────────
|
||||
; PHP-FPM Pool Configuration — MBIP Pusat Data Production
|
||||
; ─────────────────────────────────────────────────────────────
|
||||
|
||||
[www]
|
||||
|
||||
; ── Pemilik proses ───────────────────────────────────────────
|
||||
user = www-data
|
||||
group = www-data
|
||||
|
||||
; ── Dengar pada TCP (Nginx sambung melalui nama servis "app") ─
|
||||
listen = 0.0.0.0:9000
|
||||
|
||||
; ── Pengurus proses ──────────────────────────────────────────
|
||||
pm = dynamic
|
||||
|
||||
; (RAM - overhead OS) / ~20MB setiap proses PHP
|
||||
pm.max_children = 20
|
||||
pm.start_servers = 5
|
||||
pm.min_spare_servers = 5
|
||||
pm.max_spare_servers = 10
|
||||
|
||||
; Kitar semula worker untuk elak memory leak
|
||||
pm.max_requests = 500
|
||||
|
||||
; ── Log permintaan lambat ─────────────────────────────────────
|
||||
slowlog = /var/log/php-fpm/slow.log
|
||||
request_slowlog_timeout = 10s
|
||||
request_terminate_timeout = 300s
|
||||
|
||||
; ── Logging ───────────────────────────────────────────────────
|
||||
access.log = /var/log/php-fpm/access.log
|
||||
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
|
||||
|
||||
catch_workers_output = yes
|
||||
decorate_workers_output = no
|
||||
|
||||
; ── Keselamatan ──────────────────────────────────────────────
|
||||
clear_env = no
|
||||
|
||||
; ── Health check ─────────────────────────────────────────────
|
||||
ping.path = /ping
|
||||
ping.response = pong
|
||||
pm.status_path = /fpm-status
|
||||
52
docker/supervisor/supervisord.conf
Normal file
52
docker/supervisor/supervisord.conf
Normal file
@@ -0,0 +1,52 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
loglevel=warn
|
||||
|
||||
[program:php-fpm]
|
||||
command=php-fpm --nodaemonize --fpm-config /usr/local/etc/php-fpm.conf
|
||||
environment=TZ="Asia/Kuala_Lumpur"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=5
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
stopasgroup=true
|
||||
killasgroup=true
|
||||
|
||||
[program:queue-worker]
|
||||
command=php /var/www/html/artisan queue:work --sleep=3 --tries=3 --max-time=3600 --memory=128
|
||||
directory=/var/www/html
|
||||
user=www-data
|
||||
environment=TZ="Asia/Kuala_Lumpur"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=10
|
||||
startsecs=5
|
||||
startretries=3
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
stopasgroup=true
|
||||
killasgroup=true
|
||||
stopsignal=SIGTERM
|
||||
stopwaitsecs=60
|
||||
|
||||
[program:scheduler]
|
||||
command=/bin/sh -c "while true; do php /var/www/html/artisan schedule:run --verbose --no-interaction; sleep 60; done"
|
||||
directory=/var/www/html
|
||||
user=www-data
|
||||
environment=TZ="Asia/Kuala_Lumpur"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=15
|
||||
startsecs=0
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
Reference in New Issue
Block a user