Add Docker setup for production environment.
This commit is contained in:
parent
8ccbd5000d
commit
6bf2bc793b
42
docker-compose-prod.yml
Normal file
42
docker-compose-prod.yml
Normal file
@ -0,0 +1,42 @@
|
||||
version: '3.7'
|
||||
services:
|
||||
nginx:
|
||||
build:
|
||||
context: ./docker/nginx
|
||||
dockerfile: Dockerfile
|
||||
depends_on:
|
||||
- app
|
||||
- swagger
|
||||
ports:
|
||||
- ${DOCKER_CAPTCHA_NGINX_PORT}:80
|
||||
app:
|
||||
depends_on:
|
||||
- redis
|
||||
build:
|
||||
context: ./docker/app
|
||||
dockerfile: Dockerfile
|
||||
target: PRODUCTION
|
||||
# restart: always
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- SETGID
|
||||
- SETUID
|
||||
- CHOWN
|
||||
- FOWNER
|
||||
ports:
|
||||
- "9000"
|
||||
env_file: .env
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
swagger:
|
||||
image: swaggerapi/swagger-ui
|
||||
depends_on:
|
||||
- app
|
||||
environment:
|
||||
URLS: "[ { url: '/swagger.json', name: '/swagger.json' } ]"
|
||||
BASE_URL: /api-docs
|
||||
ports:
|
||||
- "8080"
|
||||
redis:
|
||||
image: redis:3.0-alpine
|
87
docker/app/Dockerfile
Normal file
87
docker/app/Dockerfile
Normal file
@ -0,0 +1,87 @@
|
||||
FROM docker.io/php:8.2-zts-alpine3.18 AS UNIT_BUILDER
|
||||
|
||||
ARG UNIT_VERSION=1.31.1
|
||||
|
||||
RUN apk --no-cache add pcre2-dev gcc git musl-dev make && \
|
||||
mkdir -p /usr/lib/unit/modules && \
|
||||
git clone https://github.com/nginx/unit.git && \
|
||||
cd unit && \
|
||||
git checkout $UNIT_VERSION && \
|
||||
./configure --prefix=/var --statedir=/var/lib/unit --runstatedir=/var/run --control=unix:/run/unit/control.unit.sock --log=/var/log/unit.log --user=www-data --group=www-data --tmpdir=/tmp --modulesdir=/var/lib/unit/modules && \
|
||||
./configure php && \
|
||||
make && \
|
||||
make install
|
||||
|
||||
FROM docker.io/php:8.2-zts-alpine3.18 as BUILD
|
||||
|
||||
COPY --from=UNIT_BUILDER /var/sbin/unitd /usr/sbin/unitd
|
||||
COPY --from=UNIT_BUILDER /var/lib/unit/ /var/lib/unit/
|
||||
|
||||
COPY docker-entrypoint.sh /home/unit/docker-entrypoint.sh
|
||||
COPY unit-config.json /docker-entrypoint.d/config.json
|
||||
|
||||
RUN apk --no-cache add pcre2 libbz2 libpng libwebp libjpeg-turbo icu-libs freetype oniguruma libzip \
|
||||
&& apk add --no-cache --virtual .phpize-deps icu-dev libpng-dev bzip2-dev libwebp-dev libjpeg-turbo-dev freetype-dev oniguruma-dev libzip-dev pcre2-dev ${PHPIZE_DEPS} \
|
||||
&& docker-php-ext-configure intl --enable-intl && \
|
||||
docker-php-ext-configure bcmath --enable-bcmath && \
|
||||
docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp && \
|
||||
docker-php-ext-install -j$(nproc) gd && \
|
||||
docker-php-ext-install bcmath &&\
|
||||
docker-php-ext-install pdo \
|
||||
mysqli pdo_mysql \
|
||||
intl mbstring \
|
||||
zip pcntl \
|
||||
exif opcache bz2 \
|
||||
calendar \
|
||||
&& pear update-channels && pecl update-channels \
|
||||
&& pecl install redis && docker-php-ext-enable redis \
|
||||
&& rm -rf /tmp/pear \
|
||||
&& docker-php-source delete \
|
||||
&& apk del .phpize-deps \
|
||||
&& rm -rf /var/cache/apk/* && rm -rf /etc/apk/cache \
|
||||
&& rm -rf /usr/share/php && rm -rf /tmp/* \
|
||||
&& rm "$PHP_INI_DIR/php.ini-development" \
|
||||
&& mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
|
||||
&& mkdir -p /tmp/php/upload \
|
||||
&& mkdir -p /tmp/php/sys \
|
||||
&& mkdir -p /tmp/php/session \
|
||||
&& chown -R www-data:www-data /tmp/php \
|
||||
&& ln -sf /dev/stdout /var/log/unit.log \
|
||||
&& addgroup -S unit && adduser -S unit -G unit \
|
||||
&& chmod 755 /home/unit/docker-entrypoint.sh
|
||||
|
||||
FROM BUILD as APP_BUILD_FOR_PRODUCTION
|
||||
WORKDIR /home/app
|
||||
RUN apk --no-cache add git nodejs npm \
|
||||
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
|
||||
&& git clone https://git.kor-elf.net/kor-elf/service-captcha.git . \
|
||||
&& composer install --optimize-autoloader --no-dev \
|
||||
&& npm install && npm run build \
|
||||
&& rm -rf /home/app/node_modules /home/app/.git /home/app/docker
|
||||
|
||||
#
|
||||
FROM BUILD AS PRODUCTION
|
||||
|
||||
COPY --from=APP_BUILD_FOR_PRODUCTION /home/app /var/www/html
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
STOPSIGNAL SIGTERM
|
||||
|
||||
ENTRYPOINT ["/home/unit/docker-entrypoint.sh"]
|
||||
EXPOSE 9000
|
||||
CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock", "--user", "unit", "--group", "unit"]
|
||||
|
||||
|
||||
#
|
||||
FROM BUILD AS DEVELOP
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
STOPSIGNAL SIGTERM
|
||||
|
||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||
|
||||
ENTRYPOINT ["/home/unit/docker-entrypoint.sh"]
|
||||
EXPOSE 9000
|
||||
CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock", "--user", "unit", "--group", "unit"]
|
111
docker/app/docker-entrypoint.sh
Normal file
111
docker/app/docker-entrypoint.sh
Normal file
@ -0,0 +1,111 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
WAITLOOPS=5
|
||||
SLEEPSEC=1
|
||||
unitd="unitd"
|
||||
|
||||
curl_put()
|
||||
{
|
||||
RET=$(/usr/bin/curl -s -w '%{http_code}' -X PUT --data-binary @$1 --unix-socket /var/run/control.unit.sock http://localhost/$2)
|
||||
RET_BODY=$(echo $RET | /bin/sed '$ s/...$//')
|
||||
RET_STATUS=$(echo $RET | /usr/bin/tail -c 4)
|
||||
if [ "$RET_STATUS" -ne "200" ]; then
|
||||
echo "$0: Error: HTTP response status code is '$RET_STATUS'"
|
||||
echo "$RET_BODY"
|
||||
return 1
|
||||
else
|
||||
echo "$0: OK: HTTP response status code is '$RET_STATUS'"
|
||||
echo "$RET_BODY"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
if [ "$unitd" = "unitd" ] || [ "$unitd" = "unitd-debug" ]; then
|
||||
echo "$0: Launching Unit daemon to perform initial configuration..."
|
||||
/usr/sbin/$unitd --control unix:/var/run/control.unit.sock
|
||||
for i in $(/usr/bin/seq $WAITLOOPS); do
|
||||
if [ ! -S /var/run/control.unit.sock ]; then
|
||||
echo "$0: Waiting for control socket to be created..."
|
||||
/bin/sleep $SLEEPSEC
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# even when the control socket exists, it does not mean unit has finished initialisation
|
||||
# this curl call will get a reply once unit is fully launched
|
||||
/usr/bin/curl -s -X GET --unix-socket /var/run/control.unit.sock http://localhost/
|
||||
|
||||
if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -print -quit 2>/dev/null | /bin/grep -q .; then
|
||||
echo "$0: /docker-entrypoint.d/ is not empty, applying initial configuration..."
|
||||
|
||||
echo "$0: Looking for certificate bundles in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.pem"); do
|
||||
echo "$0: Uploading certificates bundle: $f"
|
||||
curl_put $f "certificates/$(basename $f .pem)"
|
||||
done
|
||||
|
||||
echo "$0: Looking for JavaScript modules in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.js"); do
|
||||
echo "$0: Uploading JavaScript module: $f"
|
||||
curl_put $f "js_modules/$(basename $f .js)"
|
||||
done
|
||||
|
||||
echo "$0: Looking for configuration snippets in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.json"); do
|
||||
echo "$0: Applying configuration $f";
|
||||
curl_put $f "config"
|
||||
done
|
||||
|
||||
if [ ! -z ${UNIT_SOURCE+x} ]
|
||||
then
|
||||
echo "[${UNIT_SOURCE}]" > /docker-entrypoint.d/unit_source.json
|
||||
curl_put "/docker-entrypoint.d/unit_source.json" "config/listeners/*:9000/forwarded/source"
|
||||
fi
|
||||
|
||||
echo "$0: Looking for shell scripts in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.sh"); do
|
||||
echo "$0: Launching $f";
|
||||
"$f"
|
||||
done
|
||||
|
||||
# warn on filetypes we don't know what to do with
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -not -name "*.sh" -not -name "*.json" -not -name "*.pem" -not -name "*.js"); do
|
||||
echo "$0: Ignoring $f";
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$0: Stopping Unit daemon after initial configuration..."
|
||||
kill -TERM $(/bin/cat /var/run/unit.pid)
|
||||
|
||||
for i in $(/usr/bin/seq $WAITLOOPS); do
|
||||
if [ -S /var/run/control.unit.sock ]; then
|
||||
echo "$0: Waiting for control socket to be removed..."
|
||||
/bin/sleep $SLEEPSEC
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -S /var/run/control.unit.sock ]; then
|
||||
kill -KILL $(/bin/cat /var/run/unit.pid)
|
||||
rm -f /var/run/control.unit.sock
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "$0: Unit initial configuration complete; ready for start up..."
|
||||
echo
|
||||
fi
|
||||
|
||||
php artisan config:cache
|
||||
php artisan event:cache
|
||||
php artisan route:cache
|
||||
php artisan view:cache
|
||||
php artisan migrate --force
|
||||
|
||||
chown -R unit:unit /var/www/html
|
||||
chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
|
||||
chmod -R 777 /var/www/html/storage /var/www/html/bootstrap/cache
|
||||
|
||||
exec "$@"
|
69
docker/app/unit-config.json
Normal file
69
docker/app/unit-config.json
Normal file
@ -0,0 +1,69 @@
|
||||
{
|
||||
"listeners": {
|
||||
"*:9000": {
|
||||
"pass": "routes",
|
||||
"forwarded": {
|
||||
"client_ip": "X-Forwarded-For",
|
||||
"recursive": false,
|
||||
"source": [
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"uri": [
|
||||
"/index.php/",
|
||||
"~^/index\\.php/.*",
|
||||
"~\\.php$"
|
||||
]
|
||||
},
|
||||
"action": {
|
||||
"return": 404
|
||||
}
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"share": "/var/www/html/public$uri",
|
||||
"fallback": {
|
||||
"pass": "applications/laravel"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"applications": {
|
||||
"laravel": {
|
||||
"type": "php",
|
||||
"root": "/var/www/html/public",
|
||||
"working_directory": "/var/www/html",
|
||||
"user": "www-data",
|
||||
"group": "www-data",
|
||||
"script": "index.php",
|
||||
"processes": {
|
||||
"max": 10,
|
||||
"spare": 5,
|
||||
"idle_timeout": 20
|
||||
},
|
||||
"options": {
|
||||
"file": "/usr/local/etc/php/php.ini",
|
||||
"admin": {
|
||||
"upload_tmp_dir": "/tmp/php/upload",
|
||||
"sys_temp_dir": "/tmp/php/sys",
|
||||
"session.save_path": "/tmp/php/session",
|
||||
"open_basedir": "/var/www/html:/tmp/php:.",
|
||||
"memory_limit": "256M",
|
||||
"upload_max_filesize": "20M",
|
||||
"post_max_size": "20M",
|
||||
"expose_php": "0"
|
||||
},
|
||||
"user": {
|
||||
"display_errors": "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
docker/nginx/Dockerfile
Normal file
3
docker/nginx/Dockerfile
Normal file
@ -0,0 +1,3 @@
|
||||
FROM nginx:alpine3.18-slim
|
||||
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
36
docker/nginx/nginx.conf
Normal file
36
docker/nginx/nginx.conf
Normal file
@ -0,0 +1,36 @@
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name captcha;
|
||||
|
||||
client_max_body_size 1024M;
|
||||
|
||||
root /var/www/html/public;
|
||||
|
||||
location / {
|
||||
location /api-docs {
|
||||
proxy_pass http://swagger:8080;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-Host $http_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;
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
}
|
||||
location / {
|
||||
proxy_pass http://app:9000;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-Host $http_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;
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user