Skip to content

Commit

Permalink
Merge pull request #1143 from superfly/laravel-improvements
Browse files Browse the repository at this point in the history
Laravel docker improvements
  • Loading branch information
fideloper authored Aug 11, 2022
2 parents 74012bb + 28145a7 commit 5b9c7bc
Show file tree
Hide file tree
Showing 18 changed files with 228 additions and 1,018 deletions.
62 changes: 61 additions & 1 deletion scanner/laravel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,21 @@ package scanner

import (
"encoding/base64"

"fmt"
"github.com/superfly/flyctl/helpers"
"os/exec"
"regexp"
"strconv"
)

type ComposerLock struct {
Platform PhpVersion `json:"platform,omitempty"`
}

type PhpVersion struct {
Version string `json:"php"`
}

// setup Laravel with a sqlite database
func configureLaravel(sourceDir string) (*SourceInfo, error) {
// Laravel projects contain the `artisan` command
Expand Down Expand Up @@ -51,5 +62,54 @@ func configureLaravel(sourceDir string) (*SourceInfo, error) {
SkipDatabase: true,
}

phpVersion, err := extractPhpVersion()

if err != nil || phpVersion == "" {
// Fallback to 8.0, which has
// the broadest compatibility
phpVersion = "8.0"
}

s.BuildArgs = map[string]string{
"PHP_VERSION": phpVersion,
"NODE_VERSION": "14",
}

return s, nil
}

func extractPhpVersion() (string, error) {
/* Example Output:
PHP 8.1.8 (cli) (built: Jul 8 2022 10:58:31) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.8, Copyright (c) Zend Technologies
with Zend OPcache v8.1.8, Copyright (c), by Zend Technologies
*/
cmd := exec.Command("php", "-v")
out, err := cmd.CombinedOutput()

if err != nil {
return "", err
}

// Capture major/minor version (leaving out revision version)
re := regexp.MustCompile(`PHP ([0-9]+\.[0-9]+)\.[0-9]`)
match := re.FindStringSubmatch(string(out))

if len(match) > 1 {
// If the PHP version is below 7.4, we won't have a
// container for it, so we'll use PHP 7.4
if match[1][0:1] == "7" {
vers, err := strconv.ParseFloat(match[1], 32)
if err != nil {
return "7.4", nil
}
if vers < 7.4 {
return "7.4", nil
}
}
return match[1], nil
}

return "", fmt.Errorf("could not find php version")
}
1 change: 1 addition & 0 deletions scanner/templates/laravel/common/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ storage/logs/*
*.env*
.rr.yml
rr
vendor

# 2. Ignore common files/directories we don't need
.vscode
Expand Down
113 changes: 49 additions & 64 deletions scanner/templates/laravel/common/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,74 +1,50 @@
# syntax = docker/dockerfile:experimental

# The "base" container installs PHP, etc
FROM alpine:3.16 as base
# Default to PHP 8.1, but we attempt to match
# the PHP version from the user (wherever `flyctl launch` is run)
# Valid version values are PHP 7.4+
ARG PHP_VERSION=8.1
ARG NODE_VERSION=14
FROM serversideup/php:${PHP_VERSION}-fpm-nginx as base

LABEL fly_launch_runtime="laravel"

RUN apk update \
&& apk add curl zip unzip tzdata supervisor nginx htop vim ca-certificates rsync \
php8 php8-cli php8-pecl-mcrypt \
php8-soap php8-openssl php8-gmp \
php8-pdo_odbc php8-json php8-dom \
php8-pdo php8-zip php8-pdo_mysql \
php8-sqlite3 php8-pdo_pgsql php8-bcmath \
php8-gd php8-odbc php8-pdo_sqlite \
php8-gettext php8-xmlreader php8-bz2 \
php8-iconv php8-pdo_dblib php8-curl \
php8-ctype php8-phar php8-xml \
php8-common php8-mbstring php8-tokenizer \
php8-xmlwriter php8-fileinfo php8-opcache \
php8-simplexml php8-pecl-redis php8-sockets \
php8-pcntl php8-posix php8-pecl-swoole \
php8-fpm \
&& ln -sf /usr/bin/php8 /usr/bin/php \
&& cp /etc/nginx/nginx.conf /etc/nginx/nginx.old.conf \
&& rm -rf /etc/nginx/http.d/default.conf \
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& adduser -D -u 1000 -g 'app' app \
&& addgroup nginx app \
&& mkdir -p /var/run/php \
&& chown -R app:app /var/run/php \
&& mkdir -p /var/www/html
RUN apt-get update && apt-get install -y \
git curl zip unzip rsync ca-certificates vim htop cron \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \

WORKDIR /var/www/html
# copy application code, skipping files based on .dockerignore
COPY . /var/www/html

# Install dependencies, configure server
# For the time being, we run "composer update" as best effort to get php 8.0 working
RUN composer update \
&& composer install --optimize-autoloader --no-dev \
RUN composer install --optimize-autoloader --no-dev \
&& mkdir -p storage/logs \
&& chown -R app:app /var/www/html \
&& echo "* * * * * /usr/bin/php /var/www/html/artisan schedule:run" > /etc/crontabs/app \
&& mv docker/supervisor.conf /etc/supervisord.conf \
&& mv docker/nginx.conf /etc/nginx/nginx.conf \
&& mv docker/server.conf /etc/nginx/server.conf \
&& mv docker/php.ini /etc/php8/conf.d/php.ini \
&& sed -i 's/protected \$proxies/protected \$proxies = "*"/g' app/Http/Middleware/TrustProxies.php

# If we're not using Octane, configure php-fpm
RUN if ! grep -Fq "laravel/octane" /var/www/html/composer.json; then \
rm -rf /etc/php8/php-fpm.conf; \
rm -rf /etc/php8/php-fpm.d/www.conf; \
mv docker/php-fpm.conf /etc/php8/php-fpm.conf; \
mv docker/app.conf /etc/php8/php-fpm.d/app.conf; \
elif grep -Fq "spiral/roadrunner" /var/www/html/composer.json; then \
if [ -f ./vendor/bin/rr ]; then ./vendor/bin/rr get-binary; fi; \
rm -f .rr.yaml; \
fi

# clear Laravel cache that may be left over
RUN composer dump-autoload \
&& php artisan optimize:clear \
&& chmod -R ug+w /var/www/html/storage \
&& chmod -R 755 /var/www/html

&& chown -R webuser:webgroup /var/www/html \
&& sed -i 's/protected \$proxies/protected \$proxies = "*"/g' app/Http/Middleware/TrustProxies.php \
&& echo "MAILTO=\"\"\n* * * * * webuser /usr/bin/php /var/www/html/artisan schedule:run" > /etc/cron.d/laravel \
&& rm -rf /etc/cont-init.d/* \
&& cp docker/nginx-websockets.conf /etc/nginx/conf.d/websockets.conf \
&& cp docker/nginx-default /etc/nginx/sites-available/default \
&& cp docker/entrypoint.sh /entrypoint \
&& chmod +x /entrypoint

# If we're using Octane...
RUN if grep -Fq "laravel/octane" /var/www/html/composer.json; then \
rm -rf /etc/services.d/php-fpm; \
if grep -Fq "spiral/roadrunner" /var/www/html/composer.json; then \
mv docker/octane-rr /etc/services.d/octane; \
if [ -f ./vendor/bin/rr ]; then ./vendor/bin/rr get-binary; fi; \
rm -f .rr.yaml; \
else \
mv docker/octane-swoole /etc/services.d/octane; \
fi \
fi

# Multi-stage build: Build static assets
# This allows us to not include Node within the final container
FROM node:14 as node_modules_go_brrr
FROM node:${NODE_VERSION} as node_modules_go_brrr

RUN mkdir /app

Expand All @@ -79,27 +55,36 @@ COPY . .
# Use yarn or npm depending on what type of
# lock file we might find. Defaults to
# NPM if no lock file is found.
RUN if [ -f "yarn.lock" ]; then \
yarn install; \
# Note: We run "production" for Mix and "build" for Vite
RUN if [ -f "vite.config.js" ]; then \
ASSET_CMD="build"; \
else \
ASSET_CMD="production"; \
fi; \
if [ -f "yarn.lock" ]; then \
yarn install --frozen-lockfile; \
yarn $ASSET_CMD; \
elif [ -f "package-lock.json" ]; then \
npm ci --no-audit; \
npm run $ASSET_CMD; \
else \
npm install; \
fi
npm run $ASSET_CMD; \
fi;

# From our base container created above, we
# create our image, adding in static assets
# generated above
# create our final image, adding in static
# assets that we generated above
FROM base

# Packages like Laravel Nova may have added assets to the public directory
# or maybe some custom assets were added manually! Either way, we merge
# in the assets we generated above rather than overwrite them
COPY --from=node_modules_go_brrr /app/public /var/www/html/public-npm
RUN rsync -ar /var/www/html/public-npm/ /var/www/html/public/ \
&& rm -rf /var/www/html/public-npm
&& rm -rf /var/www/html/public-npm \
&& chown -R webuser:webgroup /var/www/html/public

# The same port nginx.conf is set to listen on and fly.toml references (standard is 8080)
EXPOSE 8080

ENTRYPOINT ["/var/www/html/docker/run.sh"]
ENTRYPOINT ["/entrypoint"]
16 changes: 16 additions & 0 deletions scanner/templates/laravel/common/docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env sh

if [ $# -gt 0 ];then
# If we passed a command, run it as root
exec "$@"
else
# Otherwise start the web server

## Prepare Laravel caches
/usr/bin/php /var/www/html/artisan config:cache --no-ansi -q
/usr/bin/php /var/www/html/artisan route:cache --no-ansi -q
/usr/bin/php /var/www/html/artisan view:cache --no-ansi -q
chown -R webuser:webgroup /var/www/html

exec /init
fi
5 changes: 5 additions & 0 deletions scanner/templates/laravel/common/docker/nginx-websockets.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# See https://laravel.com/docs/9.x/octane#reloading-the-workers
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
74 changes: 0 additions & 74 deletions scanner/templates/laravel/common/docker/nginx.conf

This file was deleted.

24 changes: 0 additions & 24 deletions scanner/templates/laravel/common/docker/php.ini

This file was deleted.

27 changes: 0 additions & 27 deletions scanner/templates/laravel/common/docker/run.sh

This file was deleted.

Loading

0 comments on commit 5b9c7bc

Please sign in to comment.