prod #119

Merged
finley merged 8 commits from prod into stg 2025-09-13 01:13:45 -07:00
10 changed files with 336 additions and 18 deletions

48
Dockerfile.prod Normal file
View file

@ -0,0 +1,48 @@
# Use the official PHP 5.6 Apache image for classic mod_php
FROM php:5.6-apache
# Install required system libraries and PHP extensions for CakePHP
RUN sed -i 's|http://deb.debian.org/debian|http://archive.debian.org/debian|g' /etc/apt/sources.list && \
sed -i 's|http://security.debian.org/debian-security|http://archive.debian.org/debian-security|g' /etc/apt/sources.list && \
sed -i '/stretch-updates/d' /etc/apt/sources.list && \
echo 'Acquire::AllowInsecureRepositories "true";' > /etc/apt/apt.conf.d/99allow-insecure && \
echo 'Acquire::AllowDowngradeToInsecureRepositories "true";' >> /etc/apt/apt.conf.d/99allow-insecure && \
apt-get update && \
apt-get install --allow-unauthenticated -y libc-client2007e-dev libkrb5-dev libpng-dev libjpeg-dev libfreetype6-dev libcurl4-openssl-dev libxml2-dev libssl-dev libmcrypt-dev libicu-dev && \
docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ && \
docker-php-ext-configure imap --with-kerberos --with-imap-ssl && \
docker-php-ext-install mysql mbstring gd curl imap
# Set environment variables.
ENV HOME /root
# Define working directory.
WORKDIR /root
ARG COMMIT
ENV COMMIT_SHA=${COMMIT}
EXPOSE 80
# Copy vhost config to Apache's sites-available
ADD conf/apache-vhost.conf /etc/apache2/sites-available/cmc-sales.conf
ADD conf/ripmime /bin/ripmime
RUN chmod +x /bin/ripmime \
&& a2ensite cmc-sales \
&& a2dissite 000-default \
&& a2enmod rewrite \
&& a2enmod headers
# Copy site into place.
ADD . /var/www/cmc-sales
ADD app/config/database.php /var/www/cmc-sales/app/config/database.php
RUN mkdir /var/www/cmc-sales/app/tmp
RUN mkdir /var/www/cmc-sales/app/tmp/logs
RUN chmod -R 755 /var/www/cmc-sales/app/tmp
RUN chmod +x /var/www/cmc-sales/run_vault.sh
# Ensure CakePHP tmp directory is writable by web server
RUN chmod -R 777 /var/www/cmc-sales/app/tmp
# By default, simply start apache.
CMD /usr/sbin/apache2ctl -D FOREGROUND

4
Dockerfile.prod.db Normal file
View file

@ -0,0 +1,4 @@
FROM mariadb:latest
COPY deploy/scripts/restore_db_from_backup.sh /docker-entrypoint-initdb.d/restore_db_from_backup.sh
RUN chmod +x /docker-entrypoint-initdb.d/restore_db_from_backup.sh

20
Dockerfile.prod.go Normal file
View file

@ -0,0 +1,20 @@
FROM golang:1.24-alpine AS builder
RUN apk add --no-cache git
WORKDIR /app
COPY go-app/go.mod go-app/go.sum ./
RUN go mod download
COPY go-app/ .
RUN go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
RUN sqlc generate
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o server cmd/server/main.go
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/server .
COPY go-app/templates ./templates
COPY go-app/static ./static
COPY go-app/.env.example .env
EXPOSE 8082
CMD ["./server"]

View file

@ -62,11 +62,21 @@ $host = $_SERVER['HTTP_HOST'];
// 'timeout' => '30',
// 'host' => '172.17.0.1'));
// SMTP settings for staging
Configure::write('smtp_settings', array(
// SMTP settings for production
if (in_array($host, $production_hosts)) {
Configure::write('smtp_settings', array(
'port' => '25',
'timeout' => '30',
'host' => '172.17.0.1'
));
} else {
// SMTP settings for staging
Configure::write('smtp_settings', array(
'port' => '1025',
'timeout' => '30',
'host' => 'mailpit'));
}
// Mailhog SMTP settings for local development

View file

@ -3,7 +3,7 @@ server {
auth_basic_user_file /etc/nginx/userpasswd;
auth_basic "Restricted";
location /go/ {
proxy_pass http://cmc-go:8080;
proxy_pass http://cmc-prod-go:8082;
proxy_read_timeout 300s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
@ -11,7 +11,7 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://cmc-php:80;
proxy_pass http://cmc-prod-php:80;
proxy_read_timeout 300s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;

26
conf/nginx-site.prod.conf Normal file
View file

@ -0,0 +1,26 @@
server {
server_name cmclocal;
auth_basic_user_file /etc/nginx/userpasswd;
auth_basic "Restricted";
location /go/ {
proxy_pass http://cmc-prod-go:8082;
proxy_read_timeout 300s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://cmc-prod-php:80;
proxy_read_timeout 300s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
listen 0.0.0.0:80;
# include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

78
deploy/deploy-prod.sh Executable file
View file

@ -0,0 +1,78 @@
#!/bin/bash
# Deploy production environment for cmc-sales
# Usage: ./deploy-prod.sh [--no-cache]
USE_CACHE=true
for arg in "$@"; do
if [[ "$arg" == "--no-cache" ]]; then
USE_CACHE=false
echo "No cache flag detected: will rebuild images without cache."
fi
done
if [[ "$USE_CACHE" == "true" ]]; then
echo "Using cached layers for docker build."
fi
echo "Starting production deployment for cmc-sales..."
echo "Setting variables..."
SERVER="cmc-sales"
REPO="git@code.springupsoftware.com:cmc/cmc-sales.git"
BRANCH="prod"
PROD_DIR="cmc-sales-prod"
echo "Connecting to server $SERVER via SSH..."
# Pass variables into SSH session
ssh $SERVER \
"SERVER=$SERVER REPO='$REPO' BRANCH='$BRANCH' PROD_DIR='$PROD_DIR' USE_CACHE='$USE_CACHE' bash -s" << 'ENDSSH'
set -e
echo "Connected to $SERVER."
cd /home/cmc
# Clone or update production branch
if [ -d "$PROD_DIR" ]; then
echo "Updating existing production directory $PROD_DIR..."
cd "$PROD_DIR"
git fetch origin
git checkout $BRANCH
git reset --hard origin/$BRANCH
else
echo "Cloning repository $REPO to $PROD_DIR..."
git clone -b $BRANCH $REPO $PROD_DIR
cd "$PROD_DIR"
fi
# Create .env file for go-app if it doesn't exist
ENV_PATH="/home/cmc/$PROD_DIR/go-app/.env"
echo "(Re)creating .env file for go-app..."
cat > "$ENV_PATH" <<'ENVEOF'
# Database configuration
DB_HOST=db
DB_PORT=3306
DB_USER=cmc
DB_PASSWORD=xVRQI&cA?7AU=hqJ!%au
DB_NAME=cmc
# Root database password (for dbshell-root)
DB_ROOT_PASSWORD=secureRootPassword
# Environment variables for Go app mail configuration
SMTP_HOST="172.17.0.1"
SMTP_PORT=25
SMTP_USER=""
SMTP_PASS=""
SMTP_FROM="CMC Sales <sales@cmctechnologies.com.au>"
ENVEOF
if [[ "$USE_CACHE" == "false" ]]; then
echo "Building and starting docker compose for production (no cache)..."
docker compose -f docker-compose.prod.yml build --no-cache
docker compose -f docker-compose.prod.yml up -d --remove-orphans
else
echo "Building and starting docker compose for production (using cache)..."
docker compose -f docker-compose.prod.yml build
docker compose -f docker-compose.prod.yml up -d --remove-orphans
fi
echo "Checking running containers..."
echo "Production deployment complete."
ENDSSH

View file

@ -1,12 +1,37 @@
#!/bin/bash
set -e
# Default to staging
TARGET="stg"
for arg in "$@"; do
if [[ "$arg" == "-target" ]]; then
NEXT_IS_TARGET=1
continue
fi
if [[ $NEXT_IS_TARGET == 1 ]]; then
TARGET="$arg"
NEXT_IS_TARGET=0
fi
done
if [[ "$TARGET" == "prod" ]]; then
DB_CONTAINER="cmc-prod-db"
DB_USER="cmc"
DB_PASS="xVRQI&cA?7AU=hqJ!%au"
DB_NAME="cmc"
else
DB_CONTAINER="cmc-db"
DB_USER="cmc"
DB_PASS="xVRQI&cA?7AU=hqJ!%au"
DB_NAME="cmc"
fi
# Sync latest backup from production
rsync -avz -e "ssh -i ~/.ssh/cmc-old" --progress cmc@sales.cmctechnologies.com.au:~/backups /home/cmc/
LATEST_BACKUP=$(ls -t /home/cmc/backups/backup_*.sql.gz | head -n1)
echo "Restoring database from latest backup: $LATEST_BACKUP"
echo "Restoring database from latest backup: $LATEST_BACKUP to $TARGET ($DB_CONTAINER)"
if [ -f "$LATEST_BACKUP" ]; then
docker cp "$LATEST_BACKUP" cmc-db:/tmp/backup.sql.gz
docker exec cmc-db sh -c "gunzip < /tmp/backup.sql.gz | mariadb -u cmc -p'xVRQI&cA?7AU=hqJ!%au' cmc"
docker cp "$LATEST_BACKUP" "$DB_CONTAINER":/tmp/backup.sql.gz
docker exec "$DB_CONTAINER" sh -c "gunzip < /tmp/backup.sql.gz | mariadb -u $DB_USER -p'$DB_PASS' $DB_NAME"
echo "Database restore complete."
else
echo "No backup file found in /home/cmc/backups. Skipping database restore."

View file

@ -1,10 +1,31 @@
#!/bin/bash
set -e
SQL_DIR="/home/cmc/cmc-sales-staging/go-app/sql/schema"
DB_USER="cmc"
DB_PASS="xVRQI&cA?7AU=hqJ!%au"
DB_NAME="cmc"
DB_HOST="127.0.0.1"
# Default to staging
TARGET="stg"
for arg in "$@"; do
if [[ "$arg" == "-target" ]]; then
NEXT_IS_TARGET=1
continue
fi
if [[ $NEXT_IS_TARGET == 1 ]]; then
TARGET="$arg"
NEXT_IS_TARGET=0
fi
done
if [[ "$TARGET" == "prod" ]]; then
DB_CONTAINER="cmc-prod-db"
DB_USER="cmc"
DB_PASS="xVRQI&cA?7AU=hqJ!%au"
DB_NAME="cmc"
SQL_DIR="/home/cmc/cmc-sales-prod/go-app/sql/schema"
else
DB_CONTAINER="cmc-db"
DB_USER="cmc"
DB_PASS="xVRQI&cA?7AU=hqJ!%au"
DB_NAME="cmc"
SQL_DIR="/home/cmc/cmc-sales-staging/go-app/sql/schema"
fi
for sqlfile in "$SQL_DIR"/*.sql; do
# Skip files starting with ignore_
@ -12,8 +33,8 @@ for sqlfile in "$SQL_DIR"/*.sql; do
echo "Skipping ignored migration: $sqlfile"
continue
fi
echo "Running migration: $sqlfile"
docker cp "$sqlfile" cmc-db:/tmp/migration.sql
docker exec cmc-db sh -c "mariadb -u $DB_USER -p'$DB_PASS' $DB_NAME < /tmp/migration.sql"
echo "Running migration: $sqlfile on $TARGET ($DB_CONTAINER)"
docker cp "$sqlfile" "$DB_CONTAINER":/tmp/migration.sql
docker exec "$DB_CONTAINER" sh -c "mariadb -u $DB_USER -p'$DB_PASS' $DB_NAME < /tmp/migration.sql"
done
echo "All migrations applied."

86
docker-compose.prod.yml Normal file
View file

@ -0,0 +1,86 @@
services:
nginx:
image: nginx:latest
container_name: cmc-prod-nginx
hostname: nginx-prod
ports:
- "8080:80" # Production nginx on port 8080 to avoid conflict
volumes:
- ./conf/nginx-site.prod.conf:/etc/nginx/conf.d/cmc.conf
- ./userpasswd:/etc/nginx/userpasswd:ro
depends_on:
- cmc-prod-php
restart: unless-stopped
networks:
- cmc-prod-network
cmc-prod-php:
build:
context: .
dockerfile: Dockerfile.prod
container_name: cmc-prod-php
environment:
MAIL_HOST: 172.17.0.1
MAIL_PORT: 25
DB_HOST: db
DB_PORT: 3306
DB_USER: cmc
DB_PASSWORD: xVRQI&cA?7AU=hqJ!%au
DB_NAME: cmc
volumes:
- ./userpasswd:/etc/nginx/userpasswd:ro
networks:
- cmc-prod-network
restart: unless-stopped
depends_on:
- db
cmc-prod-go:
build:
context: .
dockerfile: Dockerfile.prod.go
container_name: cmc-prod-go
environment:
DB_HOST: db
DB_PORT: 3306
DB_USER: cmc
DB_PASSWORD: xVRQI&cA?7AU=hqJ!%au
DB_NAME: cmc
PORT: 8082
SMTP_HOST: 172.17.0.1
SMTP_PORT: 25
SMTP_USER: ""
SMTP_PASS: ""
SMTP_FROM: "sales@cmctechnologies.com.au"
ports:
- "8083:8082"
volumes:
- /var/www/cmc-sales/app/webroot/pdf:/root/webroot/pdf:ro
networks:
- cmc-prod-network
restart: unless-stopped
depends_on:
- db
db:
build:
context: .
dockerfile: Dockerfile.prod.db
container_name: cmc-prod-db
environment:
MYSQL_ROOT_PASSWORD: secureRootPassword
MYSQL_DATABASE: cmc
MYSQL_USER: cmc
MYSQL_PASSWORD: xVRQI&cA?7AU=hqJ!%au
volumes:
- db_data:/var/lib/mysql
ports:
- "3307:3306"
networks:
- cmc-prod-network
networks:
cmc-prod-network:
volumes:
db_data: