From 4293397541e5d15004e0b5063cc1c292653a5983 Mon Sep 17 00:00:00 2001 From: Marko Korhonen Date: Fri, 21 Oct 2022 16:23:23 +0300 Subject: [PATCH] feat: add Alpine based Docker image (#43) * Gitignore .idea folder (PhpStorm etc) * Alpine version of Dockerfile * Bake definition to build Docker images * Docs for Docker image building * Link to docker.md * Use latest change on using official php-src repo and PHP-8.2 branch * Remove ARGS and get other changes from Dockerfile (original) * Update GHA workflows with Dockerfile.alpine --- .github/workflows/push.yaml | 10 ++- .github/workflows/tests.yaml | 10 ++- .gitignore | 1 + Dockerfile.alpine | 133 +++++++++++++++++++++++++++++++++++ README.md | 1 + docker-bake.hcl | 29 ++++++++ docs/docker.md | 30 ++++++++ 7 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 Dockerfile.alpine create mode 100644 docker-bake.hcl create mode 100644 docs/docker.md diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml index 7eb3749..32d6e1c 100644 --- a/.github/workflows/push.yaml +++ b/.github/workflows/push.yaml @@ -8,6 +8,9 @@ on: jobs: docker-tests: runs-on: ubuntu-latest + strategy: + matrix: + dockerfile: [ "Dockerfile", "Dockerfile.alpine" ] steps: - uses: actions/checkout@v3 with: @@ -23,7 +26,7 @@ jobs: uses: docker/build-push-action@v3 with: context: ./ - file: Dockerfile + file: ${{ matrix.dockerfile }} push: false pull: true target: builder @@ -39,6 +42,9 @@ jobs: docker run --rm frankenphp:${{ github.sha }}-builder "go test" push-image: runs-on: ubuntu-latest + strategy: + matrix: + dockerfile: [ "Dockerfile", "Dockerfile.alpine" ] steps: - uses: actions/checkout@v3 with: @@ -81,7 +87,7 @@ jobs: uses: docker/build-push-action@v3 with: context: ./ - file: Dockerfile + file: ${{ matrix.dockerfile }} push: true pull: true target: final diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 9df15ff..1fd314d 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -6,6 +6,9 @@ on: jobs: docker-tests: runs-on: ubuntu-latest + strategy: + matrix: + dockerfile: [ "Dockerfile", "Dockerfile.alpine" ] steps: - uses: actions/checkout@v3 with: @@ -21,7 +24,7 @@ jobs: uses: docker/build-push-action@v3 with: context: ./ - file: Dockerfile + file: ${{ matrix.dockerfile }} push: false pull: true target: builder @@ -37,6 +40,9 @@ jobs: docker run --rm frankenphp:${{ github.sha }}-builder "go test" push-image: runs-on: ubuntu-latest + strategy: + matrix: + dockerfile: [ "Dockerfile", "Dockerfile.alpine" ] steps: - uses: actions/checkout@v3 with: @@ -72,7 +78,7 @@ jobs: uses: docker/build-push-action@v3 with: context: ./ - file: Dockerfile + file: ${{ matrix.dockerfile }} push: false pull: true target: final diff --git a/.gitignore b/.gitignore index 3582b0f..84a9883 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /caddy/frankenphp/frankenphp /internal/testserver/testserver +.idea/ .vscode/ __debug_bin diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 0000000..352574a --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,133 @@ +FROM php:8.2.0RC4-zts-alpine3.16 AS php-base + +# Note that this image is based on the official PHP image, once 8.3 is released, this stage can likely be removed + +RUN rm -Rf /usr/local/include/php/ /usr/local/lib/libphp.* /usr/local/lib/php/ /usr/local/php/ + +ENV PHPIZE_DEPS \ + autoconf \ + dpkg-dev dpkg \ + file \ + g++ \ + gcc \ + libc-dev \ + make \ + pkgconf \ + re2c + +RUN apk add --no-cache --virtual .build-deps \ + $PHPIZE_DEPS \ + argon2-dev \ + coreutils \ + curl-dev \ + readline-dev \ + libsodium-dev \ + sqlite-dev \ + openssl-dev \ + libxml2-dev \ + gnu-libiconv-dev \ + linux-headers \ + oniguruma-dev \ + bison \ + git + +RUN git clone --depth=1 --single-branch --branch=PHP-8.2 https://github.com/php/php-src.git + +WORKDIR /php-src/ + +# --enable-embed is only necessary to generate libphp.so, we don't use this SAPI directly +RUN ./buildconf +RUN ./configure \ + --enable-embed \ + --enable-zts \ + --disable-zend-signals \ + # --enable-mysqlnd is included here because it's harder to compile after the fact than extensions are (since it's a plugin for several extensions, not an extension in itself) + --enable-mysqlnd \ + # make sure invalid --configure-flags are fatal errors instead of just warnings + --enable-option-checking=fatal \ + # https://github.com/docker-library/php/issues/439 + --with-mhash \ + # https://github.com/docker-library/php/issues/822 + --with-pic \ + # --enable-ftp is included here because ftp_ssl_connect() needs ftp to be compiled statically (see https://github.com/docker-library/php/issues/236) + --enable-ftp \ + # --enable-mbstring is included here because otherwise there's no way to get pecl to use it properly (see https://github.com/docker-library/php/issues/195) + --enable-mbstring \ + # https://wiki.php.net/rfc/argon2_password_hash + --with-password-argon2 \ + # https://wiki.php.net/rfc/libsodium + --with-sodium=shared \ + # always build against system sqlite3 (https://github.com/php/php-src/commit/6083a387a81dbbd66d6316a3a12a63f06d5f7109) + --with-pdo-sqlite=/usr \ + --with-sqlite3=/usr \ + --with-curl \ + --with-iconv \ + --with-openssl \ + --with-readline \ + --with-zlib \ + # https://github.com/bwoebi/phpdbg-docs/issues/1#issuecomment-163872806 ("phpdbg is primarily a CLI debugger, and is not suitable for debugging an fpm stack.") + --disable-phpdbg \ + --with-config-file-path="$PHP_INI_DIR" \ + --with-config-file-scan-dir="$PHP_INI_DIR/conf.d" +RUN make -j$(nproc) +RUN make install +RUN rm -Rf /php-src/ +RUN echo "Creating src archive for building extensions\n" +RUN tar -c -f /usr/src/php.tar.xz -J /php-src/ +#RUN ldconfig +RUN php --version + +FROM php-base AS builder + +COPY --from=golang:alpine3.16 /usr/local/go/bin/go /usr/local/bin/go +COPY --from=golang:alpine3.16 /usr/local/go /usr/local/go + +WORKDIR /go/src/app + +COPY go.mod go.sum ./ +RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get + +RUN mkdir caddy && cd caddy +COPY caddy/go.mod caddy/go.sum ./caddy/ + +RUN cd caddy && go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get + +COPY *.* ./ +COPY caddy caddy +COPY C-Thread-Pool C-Thread-Pool +COPY internal internal +COPY testdata testdata + +# todo: automate this? +# see https://github.com/docker-library/php/blob/master/8.2-rc/bullseye/zts/Dockerfile#L57-L59 for php values +ENV CGO_LDFLAGS="-lssl -lcrypto -lreadline -largon2 -lcurl -lonig -lz $PHP_LDFLAGS" CGO_CFLAGS=$PHP_CFLAGS CGO_CPPFLAGS=$PHP_CPPFLAGS + +RUN cd caddy/frankenphp && \ + go build && \ + cp frankenphp /usr/local/bin && \ + cp /go/src/app/caddy/frankenphp/Caddyfile /etc/Caddyfile + +ENTRYPOINT ["/bin/bash","-c"] + +FROM php:8.2.0RC4-zts-alpine3.16 AS final + +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ + +WORKDIR /app + +RUN mkdir -p /app/public +RUN echo ' /app/public/index.php + +COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp +COPY --from=builder /etc/Caddyfile /etc/Caddyfile + +COPY --from=php-base /usr/local/include/php/ /usr/local/include/php +COPY --from=php-base /usr/local/lib/libphp.* /usr/local/lib +COPY --from=php-base /usr/local/lib/php/ /usr/local/lib/php +COPY --from=php-base /usr/local/php/ /usr/local/php +COPY --from=php-base /usr/local/bin/ /usr/local/bin +COPY --from=php-base /usr/src /usr/src + +RUN sed -i 's/php/frankenphp run/g' /usr/local/bin/docker-php-entrypoint + +CMD [ "--config", "/etc/Caddyfile" ] diff --git a/README.md b/README.md index bedfab8..8f27dc0 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Go to `https://localhost`, and enjoy! * [Real-time](docs/mercure.md) * [Configuration](docs/config.md) * [Demo app (Symfony) and benchmarks](https://github.com/dunglas/frankenphp-demo) +* [Building Docker images](docs/docker.md) * [Compile from sources](docs/compile.md) * [Go library documentation](https://pkg.go.dev/github.com/dunglas/frankenphp) * [Contributing and debugging](CONTRIBUTING.md) diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000..097762e --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,29 @@ +variable "REPO_NAME" { + default = "dunglas/frankenphp" +} + +group "default" { + targets = ["bullseye", "alpine"] +} + +target "common" { + platforms = ["linux/amd64", "linux/arm64"] +} + +# +# FrankenPHP +# + +target "bullseye" { + inherits = ["common"] + context = "." + dockerfile = "Dockerfile" + tags = ["${REPO_NAME}:bullseye", "${REPO_NAME}:latest"] +} + +target "alpine" { + inherits = ["common"] + context = "." + dockerfile = "Dockerfile.alpine" + tags = ["${REPO_NAME}:alpine"] +} diff --git a/docs/docker.md b/docs/docker.md new file mode 100644 index 0000000..907708e --- /dev/null +++ b/docs/docker.md @@ -0,0 +1,30 @@ +# Building Docker images + +Print bake plan: + +``` +docker buildx bake -f docker-bake.hcl --print +``` + +Build FrankenPHP images for amd64 locally: + +``` +docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/amd64" +``` + +Build FrankenPHP images for arm64 locally: + +``` +docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/arm64" +``` + +Build FrankenPHP images from scratch for arm64 & amd64 and push to Docker Hub: + +``` +docker buildx bake -f docker-bake.hcl --pull --no-cache --push +``` + +## Resources + +* [Bake file definition](https://docs.docker.com/build/customize/bake/file-definition/) +* [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/)