Skip to content

Commit ea28a11

Browse files
committed
Add docker deployment and volumes
1 parent 171e056 commit ea28a11

8 files changed

Lines changed: 342 additions & 0 deletions

File tree

.dockerignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.git
2+
.github
3+
node_modules
4+
vendor
5+
storage/logs/*
6+
storage/framework/cache/*
7+
storage/framework/sessions/*
8+
storage/framework/views/*
9+
storage/debugbar/*
10+
storage/httpcache/*
11+
storage/streams/*
12+
storage/views/twig/*
13+
.DS_Store
14+
.env
15+
.env.*
16+
docker-compose*.yml

.github/workflows/docker-image.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Build Docker Image
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- master
8+
tags:
9+
- "v*"
10+
workflow_dispatch:
11+
12+
env:
13+
REGISTRY: ghcr.io
14+
IMAGE_NAME: nickstanko/pyrocms
15+
16+
jobs:
17+
docker:
18+
runs-on: ubuntu-latest
19+
permissions:
20+
contents: read
21+
packages: write
22+
23+
steps:
24+
- name: Check out source
25+
uses: actions/checkout@v4
26+
27+
- name: Set up QEMU
28+
uses: docker/setup-qemu-action@v3
29+
30+
- name: Set up Docker Buildx
31+
uses: docker/setup-buildx-action@v3
32+
33+
- name: Log in to GHCR
34+
uses: docker/login-action@v3
35+
with:
36+
registry: ${{ env.REGISTRY }}
37+
username: ${{ github.actor }}
38+
password: ${{ secrets.GITHUB_TOKEN }}
39+
40+
- name: Extract Docker metadata
41+
id: meta
42+
uses: docker/metadata-action@v5
43+
with:
44+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
45+
tags: |
46+
type=raw,value=latest,enable={{is_default_branch}}
47+
type=ref,event=branch
48+
type=ref,event=tag
49+
type=sha
50+
51+
- name: Build and push image
52+
uses: docker/build-push-action@v6
53+
with:
54+
context: .
55+
file: ./Dockerfile
56+
target: production
57+
push: true
58+
platforms: linux/amd64,linux/arm64
59+
tags: ${{ steps.meta.outputs.tags }}
60+
labels: ${{ steps.meta.outputs.labels }}
61+
cache-from: type=gha
62+
cache-to: type=gha,mode=max

Dockerfile

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# syntax=docker/dockerfile:1.7
2+
3+
FROM node:20-bookworm-slim AS frontend_assets
4+
WORKDIR /app
5+
COPY package.json ./
6+
RUN npm install
7+
COPY resources ./resources
8+
COPY webpack.mix.js ./
9+
RUN npm run production
10+
11+
FROM php:8.4-apache-bookworm AS base
12+
13+
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public \
14+
COMPOSER_ALLOW_SUPERUSER=1 \
15+
COMPOSER_HOME=/tmp/composer \
16+
PATH="/var/www/html/vendor/bin:${PATH}"
17+
18+
RUN apt-get update \
19+
&& apt-get install -y --no-install-recommends \
20+
curl \
21+
git \
22+
libfreetype6-dev \
23+
libicu-dev \
24+
libjpeg62-turbo-dev \
25+
libonig-dev \
26+
libpng-dev \
27+
libxml2-dev \
28+
libzip-dev \
29+
unzip \
30+
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
31+
&& docker-php-ext-install -j"$(nproc)" \
32+
bcmath \
33+
exif \
34+
gd \
35+
intl \
36+
mbstring \
37+
opcache \
38+
pdo_mysql \
39+
zip \
40+
&& pecl install redis \
41+
&& docker-php-ext-enable redis \
42+
&& a2enmod headers rewrite expires \
43+
&& rm -rf /var/lib/apt/lists/*
44+
45+
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
46+
COPY docker/apache-vhost.conf /etc/apache2/sites-available/000-default.conf
47+
COPY docker/entrypoint.sh /usr/local/bin/docker-entrypoint-app
48+
49+
RUN chmod +x /usr/local/bin/docker-entrypoint-app
50+
51+
WORKDIR /var/www/html
52+
ENTRYPOINT ["docker-entrypoint-app"]
53+
54+
FROM base AS composer_deps
55+
COPY . .
56+
RUN composer install \
57+
--no-dev \
58+
--prefer-dist \
59+
--optimize-autoloader \
60+
--no-interaction
61+
62+
FROM base AS development
63+
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
64+
CMD ["apache2-foreground"]
65+
66+
FROM base AS production
67+
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
68+
69+
COPY . .
70+
COPY --from=composer_deps /var/www/html/vendor ./vendor
71+
COPY --from=frontend_assets /app/public/css ./public/css
72+
COPY --from=frontend_assets /app/public/js ./public/js
73+
COPY --from=frontend_assets /app/public/mix-manifest.json ./public/mix-manifest.json
74+
75+
RUN chown -R www-data:www-data /var/www/html/bootstrap/cache /var/www/html/storage
76+
77+
CMD ["apache2-foreground"]

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,29 @@ curl -X POST http://localhost/api/logout \
205205
- The user provider now points at `App\UserModel`, which extends the Pyro users model and adds `HasApiTokens`.
206206
- The login endpoint uses the configured Pyro user login mode to resolve whether Passport should authenticate by username or email.
207207

208+
## Docker Volumes
209+
210+
The Docker setup supports persistent or shared mounts for the parts of the app that usually need to live outside the image:
211+
212+
- `addons/` for shared or custom PyroCMS addons
213+
- `storage/` for runtime app data
214+
- `bootstrap/cache/` for generated cache files
215+
- `public/app/` for user-managed public assets
216+
- `config/` and `resources/streams/config/` if you want host-managed config overlays
217+
218+
The default production compose file already persists:
219+
220+
- `/var/www/html/addons`
221+
- `/var/www/html/storage`
222+
- `/var/www/html/bootstrap/cache`
223+
224+
If you want host bind mounts instead of Docker-managed named volumes, uncomment the example mount lines in [docker-compose.yml](/Users/nicks/Projects/pyrocms/docker-compose.yml) and point each source path at the host directory you want to share.
225+
226+
Important:
227+
228+
- Mounting `config/` or `resources/streams/config/` replaces the image copy for those directories, so only do that when your host copy is complete.
229+
- The development compose file already bind mounts the whole repository, so local addons, config, and app data can all be edited directly there.
230+
208231
## Security
209232

210233
If you discover any security related issues, please email admin@formable.app instead of using the issue tracker.

docker-compose.dev.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
services:
2+
app:
3+
build:
4+
context: .
5+
target: development
6+
depends_on:
7+
db:
8+
condition: service_healthy
9+
redis:
10+
condition: service_started
11+
environment:
12+
APP_ENV: local
13+
APP_DEBUG: "true"
14+
APP_URL: http://localhost:8080
15+
DB_CONNECTION: mysql
16+
DB_HOST: db
17+
DB_PORT: 3306
18+
DB_DATABASE: pyrocms
19+
DB_USERNAME: pyrocms
20+
DB_PASSWORD: secret
21+
REDIS_HOST: redis
22+
REDIS_PORT: 6379
23+
CACHE_DRIVER: redis
24+
SESSION_DRIVER: redis
25+
ports:
26+
- "8080:80"
27+
volumes:
28+
- .:/var/www/html
29+
30+
node:
31+
image: node:20-bookworm-slim
32+
working_dir: /var/www/html
33+
command: sh -lc "npm install && npm run watch-poll"
34+
volumes:
35+
- .:/var/www/html
36+
37+
db:
38+
image: mysql:8.4
39+
environment:
40+
MYSQL_DATABASE: pyrocms
41+
MYSQL_USER: pyrocms
42+
MYSQL_PASSWORD: secret
43+
MYSQL_ROOT_PASSWORD: root
44+
healthcheck:
45+
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-proot"]
46+
interval: 10s
47+
timeout: 5s
48+
retries: 10
49+
start_period: 20s
50+
ports:
51+
- "3307:3306"
52+
volumes:
53+
- mysql_dev_data:/var/lib/mysql
54+
55+
redis:
56+
image: redis:7-alpine
57+
ports:
58+
- "6379:6379"
59+
volumes:
60+
- redis_dev_data:/data
61+
62+
volumes:
63+
mysql_dev_data:
64+
redis_dev_data:

docker-compose.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
services:
2+
app:
3+
image: ghcr.io/nickstanko/pyrocms:${PYROCMS_IMAGE_TAG:-latest}
4+
pull_policy: always
5+
restart: unless-stopped
6+
depends_on:
7+
db:
8+
condition: service_healthy
9+
redis:
10+
condition: service_started
11+
environment:
12+
APP_ENV: production
13+
APP_DEBUG: "false"
14+
APP_URL: ${APP_URL:-http://localhost:8080}
15+
DB_CONNECTION: mysql
16+
DB_HOST: db
17+
DB_PORT: 3306
18+
DB_DATABASE: ${DB_DATABASE:-pyrocms}
19+
DB_USERNAME: ${DB_USERNAME:-pyrocms}
20+
DB_PASSWORD: ${DB_PASSWORD:-secret}
21+
REDIS_HOST: redis
22+
REDIS_PORT: 6379
23+
CACHE_DRIVER: ${CACHE_DRIVER:-redis}
24+
SESSION_DRIVER: ${SESSION_DRIVER:-redis}
25+
ports:
26+
- "${APP_PORT:-8080}:80"
27+
volumes:
28+
- app_addons:/var/www/html/addons
29+
- app_storage:/var/www/html/storage
30+
- app_bootstrap_cache:/var/www/html/bootstrap/cache
31+
# Optional bind mounts for shared addons, app data, and config overlays:
32+
# - ./docker/volumes/addons:/var/www/html/addons
33+
# - ./docker/volumes/storage:/var/www/html/storage
34+
# - ./docker/volumes/bootstrap-cache:/var/www/html/bootstrap/cache
35+
# - ./docker/volumes/public-app:/var/www/html/public/app
36+
# - ./docker/volumes/config:/var/www/html/config
37+
# - ./docker/volumes/streams-config:/var/www/html/resources/streams/config
38+
39+
db:
40+
image: mysql:8.4
41+
restart: unless-stopped
42+
environment:
43+
MYSQL_DATABASE: ${DB_DATABASE:-pyrocms}
44+
MYSQL_USER: ${DB_USERNAME:-pyrocms}
45+
MYSQL_PASSWORD: ${DB_PASSWORD:-secret}
46+
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-root}
47+
healthcheck:
48+
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-p${DB_ROOT_PASSWORD:-root}"]
49+
interval: 10s
50+
timeout: 5s
51+
retries: 10
52+
start_period: 20s
53+
volumes:
54+
- mysql_data:/var/lib/mysql
55+
56+
redis:
57+
image: redis:7-alpine
58+
restart: unless-stopped
59+
volumes:
60+
- redis_data:/data
61+
62+
volumes:
63+
app_addons:
64+
app_storage:
65+
app_bootstrap_cache:
66+
mysql_data:
67+
redis_data:

docker/apache-vhost.conf

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<VirtualHost *:80>
2+
ServerAdmin webmaster@localhost
3+
DocumentRoot /var/www/html/public
4+
5+
<Directory /var/www/html/public>
6+
AllowOverride All
7+
Require all granted
8+
Options FollowSymLinks
9+
</Directory>
10+
11+
ErrorLog /proc/self/fd/2
12+
CustomLog /proc/self/fd/1 combined
13+
</VirtualHost>

docker/entrypoint.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/sh
2+
set -eu
3+
4+
mkdir -p \
5+
/var/www/html/addons \
6+
/var/www/html/bootstrap/cache \
7+
/var/www/html/public/app \
8+
/var/www/html/storage/app \
9+
/var/www/html/storage/debugbar \
10+
/var/www/html/storage/framework/cache \
11+
/var/www/html/storage/framework/sessions \
12+
/var/www/html/storage/framework/views \
13+
/var/www/html/storage/httpcache \
14+
/var/www/html/storage/logs \
15+
/var/www/html/storage/streams \
16+
/var/www/html/storage/views/twig
17+
18+
chown -R www-data:www-data /var/www/html/bootstrap/cache /var/www/html/storage
19+
20+
exec "$@"

0 commit comments

Comments
 (0)