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