Skip to content

Commit

Permalink
(#146) Re-wrote the docker code to generate a single self-contained d… (
Browse files Browse the repository at this point in the history
#153)

* (#146) Re-wrote the docker code to generate a single self-contained docker
image rather than using a docker-compose network of connected
containers

* (#146) Push version tags to docker hub automatically

* (#146) Switched to using a multistage docker build process to make the Dockerfile more readable and cache friendly without bloating the published image

* #146 More readable names

* #146 Documented the upgrade process and made 'artisan migrate' run on every boot to automate the upgrade process.
  • Loading branch information
donuk authored Jul 27, 2023
1 parent 524d4db commit 8f84faf
Show file tree
Hide file tree
Showing 14 changed files with 413 additions and 174 deletions.
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.git
Dockerfile
69 changes: 61 additions & 8 deletions .env.docker
Original file line number Diff line number Diff line change
@@ -1,9 +1,62 @@
POSTGRES_USER="postgres"
POSTGRES_PASSWORD="postgres"
POSTGRES_DB="postgres"

DB_HOST="database"
DB_DATABASE="postgres"
DB_USERNAME="postgres"
DB_PASSWORD="postgres"
APP_NAME="OpnForm"
APP_ENV=local
APP_KEY=
APP_DEBUG=false
APP_LOG_LEVEL=debug
APP_URL=http://localhost

LOG_CHANNEL=errorlog
LOG_LEVEL=debug

DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=postgres
DB_USERNAME=postgres
DB_PASSWORD=postgres

FILESYSTEM_DRIVER=s3
FILESYSTEM_DISK=s3

BROADCAST_DRIVER=log
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=file
SESSION_LIFETIME=120

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

JWT_TTL=1440
JWT_SECRET=

STRIPE_KEY=
STRIPE_SECRET=

MUX_WORKSPACE_ID=
MUX_API_TOKEN=

OPEN_AI_API_KEY=
26 changes: 26 additions & 0 deletions .github/workflows/dockerhub.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Publish Docker image

on:
push:
tags:
- "v*"

jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
steps:
- name: Get tag name
run: ( echo "TAG_NAME=${GITHUB_REF#refs/*/v}"; echo "DOCKER_REPO=${{secrets.DOCKER_REPO}}") >> $GITHUB_ENV

- name: Check out the repo
uses: actions/checkout@v3

- name: Log in to Docker Hub
run: docker login -u "${{ secrets.DOCKER_USERNAME }}" -p "${{ secrets.DOCKER_ACCESS_TOKEN }}"

- name: Build docker image
run: docker build . -t $DOCKER_REPO:latest -t $DOCKER_REPO:$TAG_NAME

- name: Push Docker image
run: docker push $DOCKER_REPO:latest && docker push $DOCKER_REPO:$TAG_NAME
87 changes: 87 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
ARG PHP_PACKAGES="php8.1 composer php8.1-common php8.1-pgsql php8.1-redis php8.1-mbstring\
php8.1-simplexml php8.1-bcmath php8.1-gd php8.1-curl php8.1-zip\
php8.1-imagick php8.1-bz2 php8.1-gmp php8.1-int php8.1-pcov php8.1-soap php8.1-xsl"

FROM node:16 AS javascript-builder
WORKDIR /app

# It's best to add as few files as possible before running the build commands
# as they will be re-run everytime one of those files changes.
#
# It's possible to run npm install with only the package.json and package-lock.json file.

ADD package.json package-lock.json ./
RUN npm install

ADD resources /app/resources
ADD public /app/public
ADD tailwind.config.js vite.config.js postcss.config.js /app/
RUN npm run build


# syntax=docker/dockerfile:1.3-labs
FROM --platform=linux/amd64 ubuntu:23.04 AS php-dependency-installer

ARG PHP_PACKAGES

RUN apt-get update \
&& apt-get install -y $PHP_PACKAGES composer

WORKDIR /app
ADD composer.json composer.lock artisan ./
# Running artisan requires the full php app to be installed so we need to remove the
# post-autoload command from the composer file if we want to run composer without
# adding a dependency to all the php files.
RUN sed 's_@php artisan package:discover_/bin/true_;' -i composer.json
RUN composer install

ADD app /app/app
ADD bootstrap /app/bootstrap
ADD config /app/config
ADD database /app/database
ADD public public
ADD routes routes
ADD tests tests

# Manually run the command we deleted from composer.json earlier
RUN php artisan package:discover --ansi


FROM --platform=linux/amd64 ubuntu:23.04

# supervisord is a process manager which will be responsible for managing the
# various server processes. These are configured in docker/supervisord.conf

CMD ["/usr/bin/supervisord"]

WORKDIR /app

ARG PHP_PACKAGES

RUN apt-get update \
&& apt-get install -y \
supervisor nginx sudo postgresql-15 redis\
$PHP_PACKAGES php8.1-fpm\
&& apt-get clean

ADD docker/postgres-wrapper.sh docker/php-fpm-wrapper.sh docker/redis-wrapper.sh /usr/local/bin/
ADD docker/php-fpm.conf /etc/php/8.1/fpm/pool.d/
ADD docker/nginx.conf /etc/nginx/sites-enabled/default
ADD docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
ADD .env.docker .env

ADD . .

COPY --from=javascript-builder /app/public/build/ ./public/build/
COPY --from=php-dependency-installer /app/vendor/ ./vendor/

RUN chmod a+x /usr/local/bin/*.sh /app/artisan \
&& ln -s /app/artisan /usr/local/bin/artisan \
&& useradd opnform \
&& echo "daemon off;" >> /etc/nginx/nginx.conf\
&& echo "daemonize no" >> /etc/redis/redis.conf\
&& echo "appendonly yes" >> /etc/redis/redis.conf\
&& echo "dir /persist/redis/data" >> /etc/redis/redis.conf


EXPOSE 80
43 changes: 0 additions & 43 deletions Makefile

This file was deleted.

85 changes: 67 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,35 +44,84 @@ It takes 1 minute to try out the builder for free. You'll have high availability

### Docker installation 🐳

There's a `docker compose` setup automating most of the manual steps:
There's a `Dockerfile` for building a self-contained docker image including databases, webservers etc.

This can be built and run locally but is also hosted publicly on docker hub at `jhumanj/opnform` and is generally best run directly from there.

#### Running from docker hub

```bash
make up
```
docker run --name opnform -v $PWD/my-opnform-data:/persist -p 80:80 jhumanj/opnform
```

The application is now running on [http://localhost:4000](http://localhost:4000).
Alternatively, you may use the compose setup on its own
You should now be able to access the application by visiting http://localhost in a web browser.

```bash
# Start the application
docker compose up -d server
The `-v` argument creates a local directory called `my-opnform-data` which will store your database and files so that your work is not lost when you restart the container.

The `--name` argument names the running container so that you can refer back to it later, with e.g. `docker stop opnform`. You can use any name you'd like.


#### Using a custom .env file

If you have a custom env file you can use this like so:

# Run php commands, for example
docker compose run php-cli artisan about
```
docker run --name opnform -v $PWD/my-custom-env-file.env:/app/.env -v $PWD/my-opnform-data:/persist -p 80:80 jhumanj/opnform
```

This would load load in the env file located at `my-custom-env-file.env`, note that if you are creating a .env file for use like this it's best to start from the `.docker.env` example file as there are slightly different defaults for the dockerized setup.

#### Using a custom HTTP port

To run on port 8080

# ...or update npm dependencies
docker compose run node-cli npm ci
```
docker run --name opnform -v $PWD/my-opnform-data:/persist -p 8080:80 jhumanj/opnform
```

`make` keeps track of all executed targets using `.make.*` files.
In case you'd like to start from scratch (re-install dependencies, reset jwt
token, run migrations, ...), run
#### Building a custom docker image

```bash
make clean
To build a custom docker image from your local source code use this command from the root of the source repository:

```
docker build . -t my-docker-image-name
```

After that, `make` will re-execute all targets upon the next execution.
This should create a new docker image tagged `my-docker-image-name` which can be run as follows:

```
docker run --name opnform -v $PWD/my-opnform-data:/persist -p 80:80 my-docker-image-name
```

#### Upgrading docker installations

**Please consult the upgrade instructions for the latest opnform version**, e.g. if upgrading from v1 to v2 please check the v2 instructions as the process may change in future releases.

Normal upgrade procedure would be to stop the running container, back up your data directory (you will need this backup if you want to rollback to the old version) and then start a container running the new image with the same arguments.

e.g. if you're running from a specific opnform version with

```docker run --name opnform -v $PWD/my-opnform-data:/persist -p 80:80 jhumanj/opnform:1.0.0```

You could run:

```
# stop the running container
docker stop opnform
# backup the data directory
cp -r my-opnform-data my-opnform-backup
# start the new container
docker run --name opnform-2 -v $PWD/my-opnform-data:/persist -p 80:80 jhumanj/opnform:2.0.0
```

Then if everything is running smoothly you can delete the old container with:
```
docker rm opnform
```

If you haven't specified a version e.g. if you are using the image `jhumanj/opnform` or `jhumanj/opnform:latest` you will need to run `docker pull jhumanj/opnform` or `docker pull jhumanj/opnform:latest` before starting the new container.


### Using Laravel Valet
This section explains how to get started locally with the project. It's most likely relevant if you're trying to work on the project.
Expand Down
Loading

0 comments on commit 8f84faf

Please sign in to comment.