Add Docker setup for production environment.
This commit is contained in:
		
							
								
								
									
										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; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user