Skip to content

Commit e7300c6

Browse files
authored
Merge pull request #47 from mintopia/feature/frankenphp
Update to use FrankenPHP, Laravel 12, OpenTelemetry
2 parents 899faf7 + 7857b21 commit e7300c6

File tree

93 files changed

+5866
-2464
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+5866
-2464
lines changed

.github/workflows/publish-docker-images.yml

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ env:
2020

2121

2222
jobs:
23-
build-nginx:
23+
build:
2424
runs-on: ubuntu-latest
2525
permissions:
2626
contents: read
@@ -46,7 +46,7 @@ jobs:
4646
id: meta
4747
uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
4848
with:
49-
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-nginx
49+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
5050
tags: |
5151
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
5252
type=raw,value=develop,enable=${{ github.ref == format('refs/heads/{0}', 'develop') }}
@@ -56,51 +56,7 @@ jobs:
5656
id: build-and-push
5757
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
5858
with:
59-
file: docker/production/Dockerfile.nginx
60-
context: .
61-
push: ${{ github.event_name != 'pull_request' }}
62-
tags: ${{ steps.meta.outputs.tags }}
63-
labels: ${{ steps.meta.outputs.labels }}
64-
cache-from: type=gha
65-
cache-to: type=gha,mode=max
66-
67-
build-php-fpm:
68-
runs-on: ubuntu-latest
69-
permissions:
70-
contents: read
71-
packages: write
72-
id-token: write
73-
74-
steps:
75-
- name: Checkout repository
76-
uses: actions/checkout@v3
77-
78-
- name: Set up Docker Buildx
79-
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
80-
81-
- name: Log into registry ${{ env.REGISTRY }}
82-
if: github.event_name != 'pull_request'
83-
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
84-
with:
85-
registry: ${{ env.REGISTRY }}
86-
username: ${{ github.actor }}
87-
password: ${{ secrets.GITHUB_TOKEN }}
88-
89-
- name: Extract Docker metadata
90-
id: meta
91-
uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
92-
with:
93-
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-php-fpm
94-
tags: |
95-
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
96-
type=raw,value=develop,enable=${{ github.ref == format('refs/heads/{0}', 'develop') }}
97-
type=semver,pattern={{version}}
98-
99-
- name: Build and push Docker image
100-
id: build-and-push
101-
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
102-
with:
103-
file: docker/production/Dockerfile.php-fpm
59+
file: docker/production/Dockerfile
10460
context: .
10561
push: ${{ github.event_name != 'pull_request' }}
10662
tags: ${{ steps.meta.outputs.tags }}

README.md

Lines changed: 46 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,18 @@ These are using Laravel Socialite, so any provider supported by Socialite can be
2020

2121
These are custom integrations but more can be added and used if people develop them. The Internal provider allows you to manually issue tickets to users.
2222

23-
## Setup
23+
24+
## Technology
25+
26+
This project is written in PHP 8.4 using the Laravel 12 framework. It was migrated from Laravel 10 and 11 so has some
27+
legacy project structure - but this is the intended upgrade path.
28+
29+
Horizon and Telescope are installed and enabled, with access limited to the admin role. The application itself is
30+
served using Laravel Octane and FrankenPHP.
31+
32+
Websocket communications are handled using Laravel Reverb.
33+
34+
## Development Setup
2435

2536
You will need to create a Discord application and have the Client ID and Client Secret available.
2637

@@ -43,108 +54,52 @@ You should now be able to login. The first user will be given the admin role.
4354

4455
## Production Deployment
4556

46-
I use the following docker-compose for running this in production:
47-
48-
```yaml
49-
version: '3'
50-
services:
51-
nginx:
52-
image: ghcr.io/mintopia/control-nginx:develop
53-
env_file: .env.nginx
54-
restart: unless-stopped
55-
depends_on:
56-
- php-fpm
57-
networks:
58-
- frontend
59-
- default
60-
volumes:
61-
- ./public:/var/www/storage/public
62-
63-
php-fpm:
64-
image: ghcr.io/mintopia/control-php-fpm:develop
65-
env_file: .env
66-
restart: unless-stopped
67-
depends_on:
68-
- redis
69-
- database
70-
volumes:
71-
- ./logs:/var/www/storage/logs
72-
- ./public:/var/www/storage/public
73-
74-
redis:
75-
image: redis:6.2.6
76-
restart: unless-stopped
77-
78-
database:
79-
image: mariadb:10.5-focal
80-
env_file: .env.mariadb
81-
restart: unless-stopped
82-
volumes:
83-
- ./database:/var/lib/mysql
84-
85-
worker:
86-
image: ghcr.io/mintopia/control-php-fpm:develop
87-
restart: unless-stopped
88-
deploy:
89-
replicas: 2
90-
env_file: .env
91-
depends_on:
92-
- database
93-
- redis
94-
volumes:
95-
- ./logs:/var/www/storage/logs
96-
- ./public:/var/www/storage/public
97-
entrypoint: ['php']
98-
command: 'artisan queue:work'
99-
100-
101-
scheduler:
102-
image: ghcr.io/mintopia/control-php-fpm:develop
103-
restart: unless-stopped
104-
env_file: .env
105-
depends_on:
106-
- database
107-
- redis
108-
volumes:
109-
- ./logs:/var/www/storage/logs
110-
- ./public:/var/www/storage/public
111-
entrypoint: ['php']
112-
command: 'artisan schedule:work'
113-
114-
artisan:
115-
image: ghcr.io/mintopia/control-php-fpm:develop
116-
profiles:
117-
- artisan
118-
env_file: .env
119-
depends_on:
120-
- database
121-
- redis
122-
volumes:
123-
- ./logs:/var/www/storage/logs
124-
- ./public:/var/www/storage/public
125-
entrypoint: ['php', 'artisan']
126-
127-
networks:
128-
frontend:
129-
external: true
130-
```
57+
In the `example` directory there is a docker compose file and some .env example files. These are for the setup I use.
58+
Just rename the .env files and edit them accordingly. You can get a [random Laravel application key here](https://generate-random.org/laravel-key-generator).
59+
60+
You need to expose the `control` container to the public. This is configured to listen on port 80
61+
in the docker compose, so you probably want something like Traefik or Caddy in-front as a reverse proxy.
62+
63+
I'm running this with an external docker network called `frontend` with Caddy running as HTTP/HTTPS ingress. You will
64+
need to add a network section for the `control` service to add it to the `frontend` network if you
65+
want to do this.
13166

132-
I'm running with an external docker network called `frontend` with Caddy running as HTTP/HTTPS ingress. To bring up the site, run the following:
67+
You will need to make a logs directory and chmod it 777 as I still need to sort permissions out.
13368

69+
To bring up the site, run the following:
13470

13571
```bash
136-
# Create your docker compose file
137-
# Create your .env file from the project's .env.example and edit as required.
13872
docker compose up -d redis database
139-
docker compose run --rm artisan key:generate
14073
docker compose run --rm artisan migrate
14174
docker compose run --rm artisan db:seed
142-
docker compose run --rm artisan control:setup-discord
75+
docker compose run --rm artisan setup:discord
14376
docker compose up -d
14477
```
14578

14679
You should now be able to visit the site and login. From here you can use the admin menu to configure the site.
14780

81+
## Observability
82+
83+
Control supports basic observability functionality in using an OpenTelemetry collector. It can support traces, logs
84+
and metrics. If enabled, it will create traces for all HTTP requests. To enable it, add the following to your `.env`:
85+
86+
```dotenv
87+
OPENTELEMETRY_ENABLED=true
88+
```
89+
90+
For logging output, a logger is defined and can be used. I suggest you use this with your usual logger, eg. `daily`.
91+
You can specify this logging with the following environment variables:
92+
93+
```dotenv
94+
LOG_CHANNEL=stack
95+
LOG_STACK=opentelemetry,daily
96+
```
97+
98+
By default it is configured to send to an OpenTelemetry container running with the name `collector`. An example config
99+
is supplied with placeholders for sending data to [Honeycomb](https://www.honeycomb.io/).
100+
101+
The plan will be to add further spans within individual requests and have spans for the jobs and queued actions.
102+
148103
## Contributing
149104

150105
It's an open source project and I'm happy to accept pull requests. I am terrible at UI and UX, which is why this is entirely using server-side rendering. If someone wants to use Vue/Laravel Livewire - please go ahead!

app/Console/Commands/SetupDiscord.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use App\Models\SocialProvider;
66
use App\Services\SocialProviders\DiscordProvider;
77
use Illuminate\Console\Command;
8+
89
use function Laravel\Prompts\confirm;
910
use function Laravel\Prompts\password;
1011
use function Laravel\Prompts\table;

app/Console/Commands/SyncDiscordRoles.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public function handle(?DiscordApi $discord)
6464
$query->whereSocialProviderId($discordProvider->id)
6565
->whereIn('external_id', $ids)
6666
->with(['user', 'user.tickets', 'user.tickets.type'])
67-
->chunk(100, function($accounts) use ($members) {
67+
->chunk(100, function ($accounts) use ($members) {
6868
foreach ($accounts as $linkedAccount) {
6969
$this->syncAccount($linkedAccount, $members[$linkedAccount->external_id]);
7070
}

app/Console/Commands/UpdateEventSeatingLock.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ class UpdateEventSeatingLock extends Command
2020
* The console command description.
2121
*
2222
* @var string
23-
*
23+
*
2424
*/
2525
public function handle()
2626
{
27-
Event::where('seating_opens_at', '<=', Carbon::now())->chunk(100, function($chunk) {
27+
Event::where('seating_opens_at', '<=', Carbon::now())->chunk(100, function ($chunk) {
2828
foreach ($chunk as $event) {
2929
$this->output->writeln("{$event} Unlocking seating");
3030
Log::info("{$event}: Unlocking seating");
@@ -33,7 +33,7 @@ public function handle()
3333
$event->save();
3434
}
3535
});
36-
Event::where('seating_closes_at', '<=', Carbon::now())->chunk(100, function($chunk) {
36+
Event::where('seating_closes_at', '<=', Carbon::now())->chunk(100, function ($chunk) {
3737
foreach ($chunk as $event) {
3838
$this->output->writeln("{$event} Locking seating");
3939
Log::info("{$event}: Locking seating");

app/Http/Controllers/Admin/EventController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public function create()
114114

115115
public function store(EventUpdateRequest $request)
116116
{
117-
$event = new Event;
117+
$event = new Event();
118118
$this->updateObject($event, $request);
119119
return response()->redirectToRoute('admin.events.show', $event->code)->with('successMessage', 'The event has been created');
120120
}

app/Http/Controllers/Admin/SocialProviderController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function update(SocialProviderUpdateRequest $request, SocialProvider $pro
3434
if ($provider->supports_auth) {
3535
$provider->auth_enabled = (bool)$request->input('auth_enabled');
3636
}
37-
if($provider->can_be_renamed){
37+
if ($provider->can_be_renamed) {
3838
$provider->name = $request->input('name');
3939
}
4040
$provider->save();

app/Http/Controllers/Admin/ThemeController.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public function create()
1515
if ($default) {
1616
$theme = clone $default;
1717
} else {
18-
$theme = new Theme;
18+
$theme = new Theme();
1919
}
2020
$theme->name = null;
2121
$theme->readonly = false;
@@ -27,7 +27,7 @@ public function create()
2727

2828
public function store(ThemeUpdateRequest $request)
2929
{
30-
$theme = new Theme;
30+
$theme = new Theme();
3131
$this->updateObject($theme, $request);
3232
return response()->redirectToRoute('admin.settings.index')->with('successMessage', 'The theme has been created');
3333
}
@@ -85,6 +85,5 @@ protected function updateObject(Theme $theme, Request $request)
8585
}
8686
}
8787
$theme->save();
88-
8988
}
9089
}

app/Http/Controllers/Admin/TicketController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use App\Models\TicketProvider;
1111
use App\Models\TicketType;
1212
use Illuminate\Http\Request;
13+
1314
use function App\makeCode;
1415

1516
class TicketController extends Controller
@@ -243,5 +244,4 @@ public function import_process(Request $request)
243244

244245
return response()->redirectToRoute('admin.tickets.index')->with('successMessage', 'The tickets have been imported');
245246
}
246-
247247
}

app/Http/Controllers/Controller.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88

99
class Controller extends BaseController
1010
{
11-
use AuthorizesRequests, ValidatesRequests;
11+
use AuthorizesRequests;
12+
use ValidatesRequests;
1213
}

0 commit comments

Comments
 (0)