diff --git a/.github/scripts/docker-tag-delete.sh b/.github/scripts/docker-tag-delete.sh new file mode 100755 index 00000000..7ec78a8d --- /dev/null +++ b/.github/scripts/docker-tag-delete.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +# Deletes an image tag from Docker Hub +# +# Expects USER, PASSWORD +# Expects IMAGE:TAG as argument. +# +# Example: docker-tag-delete.sh docksal/cli:php7.3-build-01c92a2-amd64 + +# Credit: +# https://devopsheaven.com/docker/dockerhub/2018/04/09/delete-docker-image-tag-dockerhub.html + +set -euo pipefail + +# Get IMAGE and TAG from first argument +if [[ "${1}" == "" ]]; then + echo "Usage: ${0} image:tag" + exit 1 +else + # Split image:tag + IFS=$':' read IMAGE TAG <<< ${1}; + # Remove registry prefix from image if present + IMAGE=${IMAGE#"docker.io/"} +fi + +login_data() { +cat < image:[version_prefix][version-]edge[-version_suffix] +# master => image:[version_prefix][version][-][version_suffix] +# semver tag => image:[version_prefix][version-]major.minor[-version_suffix] -declare -a IMAGE_TAGS +# Declare expected variables +IMAGE=${IMAGE} # docksal/cli +VERSION_PREFIX=${VERSION_PREFIX} # php +VERSION=${VERSION} # 7.4 +VERSION_SUFFIX=${VERSION_SUFFIX} # ide +REGISTRY="${REGISTRY}" # ghcr.io +GITHUB_REF=${GITHUB_REF} # refs/heads/develop, refs/heads/master, refs/tags/v1.0.0 -# feature/* => sha-xxxxxxx -# Note: disabled -#if [[ "${GITHUB_REF}" =~ "refs/heads/feature/" ]]; then -# GIT_SHA7=$(echo ${GITHUB_SHA} | cut -c1-7) # Short SHA (7 characters) -# IMAGE_TAGS+=("${REPO}:sha-${GIT_SHA7}-php${VERSION}") -# IMAGE_TAGS+=("ghcr.io/${REPO}:sha-${GIT_SHA7}-php${VERSION}") -#fi +# Join arguments with hyphen (-) as a delimiter +# Usage: join [] +join() { + local IFS='-' # join delimiter + echo "$*" +} -# develop => edge +# Prints resulting image tags and sets output variable +set_output() { + local -n inputArr=${1} + + declare -a outputArr + for imageTag in ${inputArr[@]}; do + # Prepend registry to imageTag if provided + [[ "${REGISTRY}" != "" ]] && imageTag="${REGISTRY}/${imageTag}" + outputArr+=("${imageTag}") + done + + # Print with new lines for output in build logs + (IFS=$'\n'; echo "${outputArr[*]}") + # Using newlines in output variables does not seem to work, so we'll use comas + (IFS=$','; echo "::set-output name=tags::${outputArr[*]}") +} + +# Image tags +declare -a imageTagArr + +## On every build => build / build-sha7 +## Latest build tag (used with cache-from) +#imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX} build)") +## Specific build tag - SHA7 (first 7 characters of commit SHA) +#imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX} build ${GITHUB_SHA:0:7})") + +# develop => version-edge if [[ "${GITHUB_REF}" == "refs/heads/develop" ]]; then - IMAGE_TAGS+=("${REPO}:edge-php${VERSION}") - IMAGE_TAGS+=("ghcr.io/${REPO}:edge-php${VERSION}") + imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} edge ${VERSION_SUFFIX})") fi -# master => stable +# master => version if [[ "${GITHUB_REF}" == "refs/heads/master" ]]; then - IMAGE_TAGS+=("${REPO}:stable-php${VERSION}") - IMAGE_TAGS+=("ghcr.io/${REPO}:stable-php${VERSION}") + imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX})") fi # tags/v1.0.0 => 1.0 if [[ "${GITHUB_REF}" =~ "refs/tags/" ]]; then # Extract version parts from release tag - IFS='.' read -a ver_arr <<< "${GITHUB_REF#refs/tags/}" - VERSION_MAJOR=${ver_arr[0]#v*} # 2.7.0 => "2" - VERSION_MINOR=${ver_arr[1]} # "2.7.0" => "7" - IMAGE_TAGS+=("${REPO}:stable-php${VERSION}") - IMAGE_TAGS+=("${REPO}:${VERSION_MAJOR}-php${VERSION}") - IMAGE_TAGS+=("${REPO}:${VERSION_MAJOR}.${VERSION_MINOR}-php${VERSION}") - IMAGE_TAGS+=("ghcr.io/${REPO}:stable-php${VERSION}") - IMAGE_TAGS+=("ghcr.io/${REPO}:${VERSION_MAJOR}-php${VERSION}") - IMAGE_TAGS+=("ghcr.io/${REPO}:${VERSION_MAJOR}.${VERSION_MINOR}-php${VERSION}") + IFS='.' read -a release_arr <<< "${GITHUB_REF#refs/tags/}" + releaseMajor=${release_arr[0]#v*} # 2.7.0 => "2" + releaseMinor=${release_arr[1]} # "2.7.0" => "7" + imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX})") + imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${releaseMajor} ${VERSION_SUFFIX})") + imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${releaseMajor}.${releaseMinor} ${VERSION_SUFFIX})") fi -# Output a comma concatenated list of image tags -IMAGE_TAGS_STR=$(IFS=,; echo "${IMAGE_TAGS[*]}") -echo "${IMAGE_TAGS_STR}" -echo "::set-output name=tags::${IMAGE_TAGS_STR}" +# Note: imageTagArr is passed as variable name ("reference") and then expanded inside the called function +# See https://stackoverflow.com/questions/16461656/how-to-pass-array-as-an-argument-to-a-function-in-bash/26443029#26443029 +# DockerHub tags +set_output imageTagArr diff --git a/.github/workflows/default.yaml b/.github/workflows/default.yaml index 7e2bbfaa..9da3e96b 100644 --- a/.github/workflows/default.yaml +++ b/.github/workflows/default.yaml @@ -1,149 +1,278 @@ -name: Default (push) +name: Docker Build and Push on: + schedule: + - cron: '0 10 * * 0' # everyday sunday at 10am push: branches: - master - develop - feature/* tags: - - v* + - 'v*.*.*' defaults: run: shell: bash env: - REPO: docksal/cli - LATEST_VERSION: 7.3 + IMAGE: docksal/cli + UPSTREAM_IMAGE: debian + LATEST_VERSION: '7.3' DOCKSAL_VERSION: develop jobs: - build-test-push: - name: Build, Test, Push + build: + name: "Build: ${{ matrix.version }}/${{ matrix.arch }}" runs-on: ubuntu-20.04 strategy: fail-fast: false # Don't cancel other jobs if one fails matrix: - version: - - 7.3 - - 7.4 + include: + - + platform: linux/amd64 + arch: amd64 + version: '7.3' + - + platform: linux/amd64 + arch: amd64 + version: '7.4' + - + platform: linux/amd64 + arch: amd64 + version: '8.0' + - + platform: linux/arm64 + arch: arm64 + version: '7.3' + - + platform: linux/arm64 + arch: arm64 + version: '7.4' + - + platform: linux/arm64 + arch: arm64 + version: '8.0' + + env: + ARCH: ${{ matrix.arch }} + VERSION_PREFIX: php + VERSION: ${{ matrix.version }} steps: - - - name: Install prerequisites for tests - run: | - set -xeuo pipefail - sudo apt-get -qq update - # Install cgi-fcgi binary used in tests - sudo apt-get -y --no-install-recommends install libfcgi-bin - # Install bats for tests - git clone https://github.com/bats-core/bats-core.git - cd bats-core - sudo ./install.sh /usr/local - bats -v - name: Checkout uses: actions/checkout@v2 - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + name: Environment variables + run: | + # Export variables for further steps + echo "GIT_SHA7=${GITHUB_SHA:0:7}" >> $GITHUB_ENV + echo "BUILD_IMAGE_TAG=${IMAGE}:${VERSION_PREFIX}${VERSION}-build" >> ${GITHUB_ENV} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + # Switch docker context to a remote arm64 host + name: Switch to arm64 builder host + if: ${{ env.ARCH == 'arm64' }} + uses: arwynfr/actions-docker-context@98fc92878d0b856c1112c79b8d0f45353206e186 + with: + docker_host: "ssh://ubuntu@${{ secrets.ARM64_HOST }}" + context_name: arm64-host + ssh_key: "${{ secrets.ARM64_HOST_SSH_KEY }}" + ssh_cert: "${{ secrets.ARM64_HOST_SSH_CERT }}" + use_context: true - name: Check Docker run: | docker version docker info - - name: Login to DockerHub + name: Login to Docker Hub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Login to GitHub Container Registry - uses: docker/login-action@v1 - with: - registry: ghcr.io - username: ${{ secrets.GHCR_USERNAME }} - password: ${{ secrets.GHCR_TOKEN }} -# - -# name: Build -# working-directory: ${{ matrix.version }} -# run: make buildx-with-cache - - - # Build for local use - name: Build and cache image (local) - id: docker_build + # Build and cache image in the registry + name: Build image uses: docker/build-push-action@v2 with: - context: ${{ matrix.version }} - file: ${{ matrix.version }}/Dockerfile - #platforms: linux/amd64,linux/arm64 - tags: ${{ env.REPO }}:build-php${{ matrix.version }} # Tag used locally in tests - load: true # cache image locally for use by other steps - #push: true # cannot use "push" together with "load" - cache-from: type=registry,ref=ghcr.io/${{ env.REPO }}:build-php${{ matrix.version }} + context: ${{ env.VERSION }} + file: ${{ env.VERSION }}/Dockerfile + build-args: VERSION=${{ env.VERSION }} + # Push intermediate arch-specific build tag to repo + tags: docker.io/${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-${{ env.ARCH }} + push: ${{ github.event_name != 'pull_request' }} # Don't push for PRs + # BUILD_IMAGE_TAG - persistent multi-arch tag, updated at the end of the build (success or failure) + cache-from: type=registry,ref=docker.io/${{ env.BUILD_IMAGE_TAG }} cache-to: type=inline # Write the cache metadata into the image configuration + + test: + name: "Test: ${{ matrix.version }}/${{ matrix.arch }}" + runs-on: ubuntu-20.04 + needs: build + + strategy: + fail-fast: false # Don't cancel other jobs if one fails + matrix: + include: + - + platform: linux/amd64 + arch: amd64 + version: '7.3' + - + platform: linux/amd64 + arch: amd64 + version: '7.4' + - + platform: linux/amd64 + arch: amd64 + version: '8.0' + - + platform: linux/arm64 + arch: arm64 + version: '7.3' + - + platform: linux/arm64 + arch: arm64 + version: '7.4' + - + platform: linux/arm64 + arch: arm64 + version: '8.0' + + env: + ARCH: ${{ matrix.arch }} + VERSION_PREFIX: php + VERSION: ${{ matrix.version }} + + steps: + - + name: Setup Bats + uses: mig4/setup-bats@v1 + with: + bats-version: '1.3.0' - - # Print image info - name: Image info + name: Checkout + uses: actions/checkout@v2 + - + name: Environment variables run: | - set -xeuo pipefail - docker image ls | grep "${{ env.REPO }}" - docker image inspect "${{ env.REPO }}:build-php${{ matrix.version }}" + # Export variables for further steps + echo "GIT_SHA7=${GITHUB_SHA:0:7}" >> $GITHUB_ENV + echo "BUILD_IMAGE_TAG=${IMAGE}:${VERSION_PREFIX}${VERSION}-build" >> ${GITHUB_ENV} - - # Cache image layers in the registry - name: Build and cache (ghcr.io) - uses: docker/build-push-action@v2 + # Switch docker context to a remote arm64 host + name: Switch to arm64 builder host + if: ${{ env.ARCH == 'arm64' }} + uses: arwynfr/actions-docker-context@98fc92878d0b856c1112c79b8d0f45353206e186 with: - context: ${{ matrix.version }} - file: ${{ matrix.version }}/Dockerfile - #platforms: linux/amd64,linux/arm64 - tags: ghcr.io/${{ env.REPO }}:build-php${{ matrix.version }} # Build cache tag in ghcr.io - push: ${{ github.event_name != 'pull_request' }} # Don't push for PRs - cache-to: type=inline # Write the cache metadata into the image configuration + docker_host: "ssh://ubuntu@${{ secrets.ARM64_HOST }}" + context_name: arm64-host + ssh_key: "${{ secrets.ARM64_HOST_SSH_KEY }}" + ssh_cert: "${{ secrets.ARM64_HOST_SSH_CERT }}" + use_context: true + - + name: Check Docker + run: | + docker version + docker info - # Run tests name: Test - working-directory: ${{ matrix.version }} + id: tests + working-directory: ${{ env.VERSION }} env: + BUILD_IMAGE_TAG: docker.io/${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-${{ env.ARCH }} SECRET_PLATFORMSH_CLI_TOKEN: ${{ secrets.SECRET_PLATFORMSH_CLI_TOKEN }} SECRET_TERMINUS_TOKEN: ${{ secrets.SECRET_TERMINUS_TOKEN }} - run: make test + run: | + make test + ([[ $? == 0 ]] && echo "pass" || echo "fail") | tee ${{ github.workspace }}/test-results-${VERSION_PREFIX}${VERSION}-${ARCH}.txt + # Store tests results as an artifact (used by downstream jobs) + # Note: Cannot use "::set-output name=var_name::var_value" as var_name would need to be dynamic here. + # Dynamic variable names cannot be used when mapping step outputs to job outputs. + # Step outputs cannot be accessed directly from other jobs. Dead end. + - name: Store test results + uses: actions/upload-artifact@v2 + with: + name: test-results + path: ${{ github.workspace }}/test-results-*.txt + + push: + name: "Push: ${{ matrix.version }}/multi" + runs-on: ubuntu-20.04 + + # Wait for test to either succeed or fail + needs: test + if: always() + + strategy: + matrix: + version: + - '7.3' + - '7.4' + - '8.0' + + env: + VERSION_PREFIX: php + VERSION: ${{ matrix.version }} + + steps: - - # Generate image meta information - name: Image tags + name: Checkout + uses: actions/checkout@v2 + - + name: Environment variables + run: | + # Export variables for further steps + echo "GIT_SHA7=${GITHUB_SHA:0:7}" >> $GITHUB_ENV + echo "BUILD_IMAGE_TAG=${IMAGE}:${VERSION_PREFIX}${VERSION}-build" >> ${GITHUB_ENV} + - + # Login to Docker Hub + name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Retrieve test results + uses: actions/download-artifact@v2 + with: + name: test-results + - + # Generate persistent tags (edge, stable, release) + name: Docker image tags id: docker_tags - working-directory: ${{ matrix.version }} + # Don't push broken builds to persistent tags (both amd64 and arm64 tests must pass) + run: | + amd64_tests=$(cat test-results-${VERSION_PREFIX}${VERSION}-amd64.txt) + arm64_tests=$(cat test-results-${VERSION_PREFIX}${VERSION}-arm64.txt) + if [[ "${amd64_tests}" == "pass" ]] && [[ "${arm64_tests}" == "pass" ]]; then + .github/scripts/docker-tags.sh + fi + - + # Create and push multi-arch image manifests + name: Push multi-arch images env: - VERSION: ${{ matrix.version }} - run: make tags -# - -# # Push image to registries -# name: Push image (Docker Hub and GitHub Container Registry) -# working-directory: ${{ matrix.version }} -# run: make release - - - # Push image to registries - name: Push image to registries - id: docker_push - # Don't run if the list of tags is empty - # Tags are only generated for develop, master and release tag builds - if: ${{ steps.docker_tags.outputs.tags != '' }} - uses: docker/build-push-action@v2 - with: - context: ${{ matrix.version }} - file: ${{ matrix.version }}/Dockerfile - #platforms: linux/amd64,linux/arm64 - # Tag and push to Docker Hub and GitHub Container Registry - tags: ${{ steps.docker_tags.outputs.tags }} - labels: | - org.opencontainers.image.source=${{ github.event.repository.html_url }} - org.opencontainers.image.created=${{ steps.prep.outputs.created }} - org.opencontainers.image.revision=${{ github.sha }} - push: ${{ github.event_name != 'pull_request' }} # Don't push for PRs - cache-to: type=inline # Write the cache metadata into the image configuration + # build tags are always pushed (build caching, debugging needs) + # edge, stage, release are only pushed if tests were successful (see docker_tags step) + TAGS: | + ${{ env.BUILD_IMAGE_TAG }} + ${{ steps.docker_tags.outputs.tags }} + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} # Needed for docker-tag-delete.sh + DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} # Needed for docker-tag-delete.sh + run: | + set -xeuo pipefail + IFS="${IFS}," # Also split strings by comma (in case list of tag is comma-separated) + for tag in ${TAGS}; do + if [[ "${tag}" == "" ]]; then continue; fi + docker manifest create --amend ${tag} \ + ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-amd64 \ + ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-arm64 + docker manifest inspect ${tag} + docker manifest push ${tag} + done + # Clean up intermediate arch-specific image tags (DockerHub only) + .github/scripts/docker-tag-delete.sh ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-amd64 + .github/scripts/docker-tag-delete.sh ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-arm64 diff --git a/.travis-legacy.yml b/.travis-legacy.yml deleted file mode 100644 index ebb66358..00000000 --- a/.travis-legacy.yml +++ /dev/null @@ -1,41 +0,0 @@ -dist: bionic - -language: minimal - -env: - global: - - REPO=docksal/cli - - LATEST_VERSION=7.3 - - DOCKSAL_VERSION=develop - matrix: - - VERSION=7.3 - - VERSION=7.4 - -# Skip building master. -# Stable image tags are pushed during release tag builds so that stable and release tags match on Docker Hub. -branches: - except: - - master - -before_install: - - sudo apt-get -qq update - - sudo apt-get install libfcgi0ldbl # cgi-fcgi binary used in tests - -install: - # Install Docksal to have a matching versions of Docker on the build host - - curl -fsSL https://get.docksal.io | DOCKSAL_VERSION=${DOCKSAL_VERSION} bash - - fin version - - fin sysinfo - -script: - - cd ${TRAVIS_BUILD_DIR}/${VERSION} - - travis_retry make build # Retry builds, as pecl.php.net tends to time out often - - make test - -after_success: - - docker image ls - - make release - -after_failure: - - cd ${TRAVIS_BUILD_DIR}/${VERSION} && make logs - - cd ${TRAVIS_BUILD_DIR}/code-server && make logs diff --git a/7.3/.dockerignore b/7.3/.dockerignore index 69e0091b..0123c988 100644 --- a/7.3/.dockerignore +++ b/7.3/.dockerignore @@ -1,4 +1,4 @@ +tests .dockerignore Dockerfile Makefile -php-modules.txt diff --git a/7.3/Dockerfile b/7.3/Dockerfile index 021cf76e..364f4ca5 100644 --- a/7.3/Dockerfile +++ b/7.3/Dockerfile @@ -1,5 +1,6 @@ FROM php:7.3-fpm-buster as cli +ARG TARGETARCH ARG DEBIAN_FRONTEND=noninteractive ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 @@ -35,10 +36,7 @@ RUN set -xe; \ echo "deb https://packages.blackfire.io/debian any main" | tee /etc/apt/sources.list.d/blackfire.list; \ # git-lfs repo curl -fsSL https://packagecloud.io/github/git-lfs/gpgkey | apt-key add -; \ - echo 'deb https://packagecloud.io/github/git-lfs/debian buster main' | tee /etc/apt/sources.list.d/github_git-lfs.list; \ - # MSQSQL repo - msodbcsql17, pecl/sqlsrv and pecl/pdo_sqlsrv (PHP 7.0+ only) - curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | apt-key add -; \ - echo 'deb https://packages.microsoft.com/debian/10/prod buster main' | tee /etc/apt/sources.list.d/mssql.list; + echo 'deb https://packagecloud.io/github/git-lfs/debian buster main' | tee /etc/apt/sources.list.d/github_git-lfs.list; # Additional packages RUN set -xe; \ @@ -87,16 +85,16 @@ RUN set -xe; \ echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers ENV GOSU_VERSION=1.12 \ - GOMPLATE_VERSION=3.8.0 + GOMPLATE_VERSION=3.9.0 RUN set -xe; \ # Install gosu and give access to the docker user primary group to use it. # gosu is used instead of sudo to start the main container process (pid 1) in a docker friendly way. # https://github.com/tianon/gosu - curl -fsSL "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-$(dpkg --print-architecture)" -o /usr/local/bin/gosu; \ - chown root:"$(id -gn docker)" /usr/local/bin/gosu; \ + curl -fsSL https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${TARGETARCH} -o /usr/local/bin/gosu; \ + chown root:$(id -gn docker) /usr/local/bin/gosu; \ chmod +sx /usr/local/bin/gosu; \ # gomplate (to process configuration templates in startup.sh) - curl -fsSL https://github.com/hairyhenderson/gomplate/releases/download/v${GOMPLATE_VERSION}/gomplate_linux-amd64-slim -o /usr/local/bin/gomplate; \ + curl -fsSL https://github.com/hairyhenderson/gomplate/releases/download/v${GOMPLATE_VERSION}/gomplate_linux-${TARGETARCH} -o /usr/local/bin/gomplate; \ chmod +x /usr/local/bin/gomplate # Configure sshd (for use PHPStorm's remote interpreters and tools integrations) @@ -136,8 +134,6 @@ RUN set -xe; \ unixodbc-dev \ "; \ apt-get update >/dev/null; \ - # Necessary for msodbcsql17 (MSSQL) - ACCEPT_EULA=Y \ apt-get -y --no-install-recommends install >/dev/null \ $buildDeps \ blackfire-php \ @@ -158,11 +154,7 @@ RUN set -xe; \ libxpm4 \ libxslt1.1 \ libzip4 \ - msodbcsql17 \ ;\ - # SSH2 must be installed from source for PHP 7.x - git clone https://github.com/php/pecl-networking-ssh2.git /usr/src/php/ext/ssh2 && rm -rf /usr/src/php/ext/ssh2/.git; \ - \ docker-php-ext-configure >/dev/null gd \ --with-freetype-dir=/usr/include/ \ --with-jpeg-dir=/usr/include/ \ @@ -170,7 +162,8 @@ RUN set -xe; \ --with-png-dir=/usr/include/ \ --with-xpm-dir=/usr/include/; \ docker-php-ext-configure >/dev/null imap --with-kerberos --with-imap-ssl; \ - docker-php-ext-configure >/dev/null ldap --with-libdir=lib/x86_64-linux-gnu/; \ + # Using $(uname -m) (returns x86_64 / aarch64) vs ${TARGETARCH} (returns amd64 / arm64) + docker-php-ext-configure >/dev/null ldap --with-libdir=lib/$(uname -m)-linux-gnu/; \ docker-php-ext-configure >/dev/null pgsql --with-pgsql=/usr/local/pgsql/; \ docker-php-ext-configure >/dev/null zip --with-libzip; \ \ @@ -192,7 +185,6 @@ RUN set -xe; \ pgsql \ soap \ sockets \ - ssh2 \ xsl \ zip \ sysvsem \ @@ -204,9 +196,8 @@ RUN set -xe; \ imagick \ # Use memcached (not memcache) for PHP 7.x memcached \ - pdo_sqlsrv \ redis \ - sqlsrv \ + ssh2-beta \ xdebug \ xhprof \ ;\ @@ -215,9 +206,8 @@ RUN set -xe; \ gnupg \ imagick \ memcached \ - pdo_sqlsrv \ redis \ - sqlsrv \ + ssh2 \ ;\ # Cleanup docker-php-source delete; \ @@ -225,20 +215,52 @@ RUN set -xe; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $buildDeps >/dev/null; \ apt-get clean; rm -rf /var/lib/apt/lists/* +# Packages not available for arm64 +RUN set -xe; \ + if [ "${TARGETARCH}" = "amd64" ]; then \ + # MSQSQL repo - msodbcsql17, pecl/sqlsrv and pecl/pdo_sqlsrv (PHP 7.0+ only) + curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | apt-key add -; \ + echo 'deb https://packages.microsoft.com/debian/10/prod buster main' | tee /etc/apt/sources.list.d/mssql.list; \ + \ + buildDeps=" \ + unixodbc-dev \ + "; \ + apt-get update >/dev/null; \ + # Necessary for msodbcsql17 (MSSQL) + ACCEPT_EULA=Y \ + apt-get -y --no-install-recommends install >/dev/null \ + $buildDeps \ + msodbcsql17 \ + ;\ + pecl update-channels; \ + pecl install >/dev/null /dev/null; \ + apt-get clean; rm -rf /var/lib/apt/lists/*; \ + fi + # PHP tools (installed globally) ENV COMPOSER_DEFAULT_VERSION=2 \ - COMPOSER_VERSION=1.10.19 \ - COMPOSER2_VERSION=2.0.8 \ - DRUSH_VERSION=8.4.5 \ - DRUSH_LAUNCHER_VERSION=0.8.0 \ + COMPOSER_VERSION=1.10.22 \ + COMPOSER2_VERSION=2.1.5 \ + DRUSH_VERSION=8.4.8 \ + DRUSH_LAUNCHER_VERSION=0.9.1 \ DRUPAL_CONSOLE_LAUNCHER_VERSION=1.9.7 \ - WPCLI_VERSION=2.4.0 \ - BLACKFIRE_VERSION=1.44.1 \ - PLATFORMSH_CLI_VERSION=3.63.3 \ - ACQUIA_CLI_VERSION=1.3.0 \ - TERMINUS_VERSION=2.4.1 \ + WPCLI_VERSION=2.5.0 \ + BLACKFIRE_VERSION=1.49.3 \ + PLATFORMSH_CLI_VERSION=3.66.0 \ + ACQUIA_CLI_VERSION=1.13.1 \ + TERMINUS_VERSION=2.6.0 \ JQ_VERSION=1.6 \ - YQ_VERSION=3.4.1 + YQ_VERSION=4.11.2 RUN set -xe; \ # Composer 1.x curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER_VERSION}/composer.phar" -o /usr/local/bin/composer1; \ @@ -253,38 +275,58 @@ RUN set -xe; \ # Wordpress CLI curl -fsSL "https://github.com/wp-cli/wp-cli/releases/download/v${WPCLI_VERSION}/wp-cli-${WPCLI_VERSION}.phar" -o /usr/local/bin/wp; \ # Blackfire CLI - curl -fsSL "https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_VERSION}/blackfire-cli-linux_static_amd64" -o /usr/local/bin/blackfire; \ + curl -fsSL "https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_VERSION}/blackfire-cli-linux_${TARGETARCH}" -o /usr/local/bin/blackfire; \ # Platform.sh CLI curl -fsSL "https://github.com/platformsh/platformsh-cli/releases/download/v${PLATFORMSH_CLI_VERSION}/platform.phar" -o /usr/local/bin/platform; \ # Acquia CLI curl -fsSL "https://github.com/acquia/cli/releases/download/${ACQUIA_CLI_VERSION}/acli.phar" -o /usr/local/bin/acli; \ # Pantheon Terminus curl -fsSL "https://github.com/pantheon-systems/terminus/releases/download/${TERMINUS_VERSION}/terminus.phar" -o /usr/local/bin/terminus; \ - # jq - curl -fsSL "https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64" -o /usr/local/bin/jq; \ + # jq (no arm64) + if [ "${TARGETARCH}" = "amd64" ]; then \ + curl -fsSL "https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64" -o /usr/local/bin/jq; \ + chmod +x /usr/local/bin/jq; \ + fi; \ # yq - curl -fsSL "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64" -o /usr/local/bin/yq; \ + curl -fsSL "https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_${TARGETARCH}" -o /usr/local/bin/yq; \ # Set Default Composer Version ln -s /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer; \ # Make all downloaded binaries executable in one shot - (cd /usr/local/bin && chmod +x composer1 composer2 drush8 drush drupal wp blackfire platform acli terminus jq yq); + (cd /usr/local/bin && chmod +x composer1 composer2 drush8 drush drupal wp blackfire platform acli terminus yq); + +# Install Python3 from Debian repos +# This adds about 30MB to uncompressed image size. +# TODO: some other dependency in this image installs python2. Which one? +RUN set -xe; \ + apt-get update >/dev/null; \ + apt-get -y --no-install-recommends install >/dev/null \ + python3 \ + ;\ + # Cleanup + apt-get clean; rm -rf /var/lib/apt/lists/* + +# Install Ruby from Debian repos +RUN set -xe; \ + apt-get update >/dev/null; \ + apt-get -y --no-install-recommends install >/dev/null \ + ruby-full \ + ;\ + # Cleanup + apt-get clean; rm -rf /var/lib/apt/lists/* # All further RUN commands will run as the "docker" user USER docker SHELL ["/bin/bash", "-c"] -# PHP tools (installed as user) -# Note: DRUSH_BACKDROP_VERSION should be pinned at 1.2.0 as 1.3.0 introduces changes that break regular drush 8. -ENV \ - MG_CODEGEN_VERSION=1.11.2 \ - DRUSH_BACKDROP_VERSION=1.2.0 # Don't use -x here, as the output may be excessive RUN set -e; \ \ # Set drush8 as a global fallback for Drush Launcher echo -e "\n""export DRUSH_LAUNCHER_FALLBACK=/usr/local/bin/drush8" >> $HOME/.profile; \ # Composer based dependencies - # Add composer bin directory to PATH + # Add composer bin project level and global directories to PATH + # Project level comes first and thus takes precedence over the global one + echo -e "\n"'export PATH="$PATH:${PROJECT_ROOT:-/var/www}/vendor/bin"' >> $HOME/.profile; \ echo -e "\n"'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> $HOME/.profile; \ # Reload updated PATH from profile to make composer/drush/etc. visible below . $HOME/.profile; \ @@ -297,25 +339,13 @@ $HOME/.composer/vendor/wp-coding-standards/wpcs/,\ $HOME/.composer/vendor/phpcompatibility/php-compatibility/PHPCompatibility/,\ $HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp/PHPCompatibilityWP,\ $HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie/PHPCompatibilityParagonieRandomCompat; \ - # Install cgr to use it in-place of `composer global require` for misc globally installed cli tools. - # See https://pantheon.io/blog/fixing-composer-global-command - composer global require consolidation/cgr >/dev/null; \ - # Magento2 Code Generator - # Cannot be properly installed and used as a phar binary - # See https://github.com/staempfli/magento2-code-generator/issues/11 - cgr staempfli/magento2-code-generator:${MG_CODEGEN_VERSION} >/dev/null; \ # Cleanup - composer clear-cache; \ - \ - # Drush modules - drush dl registry_rebuild --default-major=7 --destination=$HOME/.drush >/dev/null; \ - mkdir $HOME/.drush/backdrop && curl -fsSL "https://github.com/backdrop-contrib/backdrop-drush-extension/archive/${DRUSH_BACKDROP_VERSION}.tar.gz" | tar xz -C $HOME/.drush/backdrop --strip-components 1; \ - drush cc drush + composer clear-cache # Node.js (installed as user) ENV \ - NVM_VERSION=0.37.2 \ - NODE_VERSION=14.15.1 \ + NVM_VERSION=0.38.0 \ + NODE_VERSION=14.17.3 \ YARN_VERSION=1.22.10 # Don't use -x here, as the output may be excessive RUN set -e; \ @@ -328,61 +358,79 @@ RUN set -e; \ export YARN_PROFILE="$HOME/.profile"; \ curl -fsSL https://yarnpkg.com/install.sh | bash -s -- --version ${YARN_VERSION} >/dev/null -# Ruby (installed as user) -ENV \ - RVM_VERSION_INSTALL=1.29.10 \ - RUBY_VERSION_INSTALL=2.7.2 -# Don't use -x here, as the output may be excessive -RUN set -e; \ - # Public GPG servers are not realiable, so downloading keys from rvm.io instead. - #gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB - # Import and trust rvm keys - # mpapis@gmail.com - curl -sSL https://rvm.io/mpapis.asc | gpg --batch --import -; \ - echo 409B6B1796C275462A1703113804BB82D39DC0E3:6: | gpg --batch --import-ownertrust; \ - # piotr.kuczynski@gmail.com - curl -sSL https://rvm.io/pkuczynski.asc | gpg --batch --import -; \ - echo 7D2BAF1CF37B13E2069D6956105BD0E739499BDB:6: | gpg --batch --import-ownertrust; \ - \ - echo 'rvm_autoupdate_flag=0' >> $HOME/.rvmrc; \ - echo 'rvm_silence_path_mismatch_check_flag=1' >> $HOME/.rvmrc; \ - curl -fsSL https://raw.githubusercontent.com/rvm/rvm/${RVM_VERSION_INSTALL}/binscripts/rvm-installer | bash -s -- --ignore-dotfiles --version ${RVM_VERSION_INSTALL}; \ - { \ - echo ''; \ - echo 'export PATH="$PATH:$HOME/.rvm/bin"'; \ - echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"'; \ - } >> $HOME/.profile; \ - # Reload $HOME/.profile to apply settings for the current shell - . $HOME/.profile; \ - \ - # rvm.io does not currently have ruby binaries for Debian 9, so Ruby is compiled from source, which requires a bunch - # of extra dependencies installed (rvm installs these automatically), which bloat this image: - # rvm/ruby required packages: gawk, automake, bison, libffi-dev, libgdbm-dev, libncurses5-dev, libsqlite3-dev, libtool, libyaml-dev, sqlite3, zlib1g-dev, libgmp-dev, libreadline-dev, libssl-dev - rvm install ruby-${RUBY_VERSION_INSTALL}; \ - rvm use ruby-${RUBY_VERSION_INSTALL} --default; \ - \ - gem install bundler; \ - # Have bundler install gems locally (./.bundle) by default - echo -e "\n"'export BUNDLE_PATH=.bundle' >> $HOME/.profile; \ - \ - rvm cleanup all; \ - rvm gemset globalcache enable - -# Python (installed as user) -ENV \ - PYENV_VERSION_INSTALL=1.2.21 +## Ruby (installed as user) via rvm +## Note: Disabled. rvm + its build dependecies bloat the image (~80MB) +## Debian 10 ships with Ruby 2.5, so we'll stick with that by default. +## It is still possible for the end user to switch to a different Ruby version via rvm. +#ENV \ +# RVM_VERSION_INSTALL=1.29.10 \ +# RUBY_VERSION_INSTALL=2.7.2 +## Don't use -x here, as the output may be excessive +#RUN set -e; \ +# # Export ruby gem bin path +# echo 'export PATH=$PATH:$(ruby -r rubygems -e "puts Gem.user_dir")/bin' >> $HOME/.profile; \ +# . $HOME/.profile; \ +# # Public GPG servers are not realiable, so downloading keys from rvm.io instead. +# #gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB +# # Import and trust rvm keys +# # mpapis@gmail.com +# curl -sSL https://rvm.io/mpapis.asc | gpg --batch --import -; \ +# echo 409B6B1796C275462A1703113804BB82D39DC0E3:6: | gpg --batch --import-ownertrust; \ +# # piotr.kuczynski@gmail.com +# curl -sSL https://rvm.io/pkuczynski.asc | gpg --batch --import -; \ +# echo 7D2BAF1CF37B13E2069D6956105BD0E739499BDB:6: | gpg --batch --import-ownertrust; \ +# \ +# echo 'rvm_autoupdate_flag=0' >> $HOME/.rvmrc; \ +# echo 'rvm_silence_path_mismatch_check_flag=1' >> $HOME/.rvmrc; \ +# curl -fsSL https://raw.githubusercontent.com/rvm/rvm/${RVM_VERSION_INSTALL}/binscripts/rvm-installer | bash -s -- --ignore-dotfiles --version ${RVM_VERSION_INSTALL}; \ +# { \ +# echo ''; \ +# echo 'export PATH="$PATH:$HOME/.rvm/bin"'; \ +# echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"'; \ +# } >> $HOME/.profile; \ +# # Reload $HOME/.profile to apply settings for the current shell +# . $HOME/.profile; \ +# \ +# # rvm.io does not currently have ruby binaries for Debian 9, so Ruby is compiled from source, which requires a bunch +# # of extra dependencies installed (rvm installs these automatically), which bloat this image: +# # rvm/ruby required packages: gawk, automake, bison, libffi-dev, libgdbm-dev, libncurses5-dev, libsqlite3-dev, libtool, libyaml-dev, sqlite3, zlib1g-dev, libgmp-dev, libreadline-dev, libssl-dev +# rvm install ruby-${RUBY_VERSION_INSTALL}; \ +# rvm use ruby-${RUBY_VERSION_INSTALL} --default; \ +# \ +# gem install --user-install bundler; \ +# # Have bundler install gems locally (./.bundle) by default +# echo -e "\n"'export BUNDLE_PATH=.bundle' >> $HOME/.profile; \ +# \ +# rvm cleanup all; \ +# rvm gemset globalcache enable + +# Python (installed as user) via pyenv +# Note: Disabled. pyenv + its build dependecies bloat the image (~300MB). +# Debian 10 ships with Python 3.7, so we'll stick with that by default. +# It is still possible for the end user to switch to a different python version via pyenv. +#ENV \ +# PYENV_VERSION_INSTALL=1.2.21 \ # PYTHON_VERSION_INSTALL=3.8.3 -RUN set -xe; \ - git clone --depth 1 -b v${PYENV_VERSION_INSTALL} https://github.com/pyenv/pyenv.git $HOME/.pyenv; \ - rm -rf $HOME/.pyenv/.git; \ - { \ - echo ''; \ - echo 'export PYENV_ROOT="$HOME/.pyenv"'; \ - echo 'export PATH="$PYENV_ROOT/bin:$PATH"'; \ - echo 'eval "$(pyenv init -)"'; \ - } >> $HOME/.profile -# Disabled for now - uses too much space (~200MB). -# The upsteam Debian 9 image ships with Python 2.7 out of the box, so we'll stick with that by default. +#RUN set -xe; \ +# # pyenv requires a bunch of build dependencies installed, which would bloat this image +# # See https://github.com/pyenv/pyenv/wiki/Common-build-problems#prerequisites +# sudo apt-get update >/dev/null; \ +# sudo apt-get -y --no-install-recommends install >/dev/null \ +# build-essential libssl-dev zlib1g-dev libbz2-dev \ +# libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \ +# xz-utils tk-dev libffi-dev liblzma-dev python-openssl git \ +# ;\ +# # Cleanup +# sudo apt-get clean; sudo rm -rf /var/lib/apt/lists/*; \ +# \ +# git clone --depth 1 -b v${PYENV_VERSION_INSTALL} https://github.com/pyenv/pyenv.git $HOME/.pyenv; \ +# rm -rf $HOME/.pyenv/.git; \ +# { \ +# echo ''; \ +# echo 'export PYENV_ROOT="$HOME/.pyenv"'; \ +# echo 'export PATH="$PYENV_ROOT/bin:$PATH"'; \ +# echo 'eval "$(pyenv init -)"'; \ +# } >> $HOME/.profile; \ # # Reload $HOME/.profile to apply settings for the current shell # . $HOME/.profile; \ # pyenv install ${PYTHON_VERSION_INSTALL}; \ @@ -453,28 +501,25 @@ USER docker ARG HOME=/home/docker ENV \ - CODE_SERVER_VERSION=3.7.4 \ - VSCODE_HOME="${HOME}/code-server" \ - VSCODE_EXT_DIRECTORY="${HOME}/code-server/extensions" \ - VSCODE_XDEBUG_VERSION=1.13.0 \ - VSCODE_GITLENS_VERSION=11.0.6 + CODE_SERVER_VERSION=3.11.0 \ + VSCODE_XDEBUG_VERSION=1.16.1 \ + VSCODE_GITLENS_VERSION=11.6.0 \ + VSCODE_HOME="${HOME}/code-server" # Install code-server -RUN \ - set -xe; \ - curl -fsSL "https://github.com/cdr/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server_${CODE_SERVER_VERSION}_amd64.deb" -o /tmp/code-server_amd64.deb; \ - sudo dpkg -i /tmp/code-server_amd64.deb; \ +RUN set -xe; \ + curl -fsSL "https://github.com/cdr/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server_${CODE_SERVER_VERSION}_${TARGETARCH}.deb" -o /tmp/code-server_${TARGETARCH}.deb; \ + sudo dpkg -i /tmp/code-server_${TARGETARCH}.deb; \ rm -rf /tmp/*.* -# Settings and scripts -COPY --chown=docker:docker opt/code-server /opt/code-server +# Settings +COPY --chown=docker:docker config/code-server ${VSCODE_HOME} # Install extensions -RUN \ - set -xe; \ - mkdir -p ${VSCODE_EXT_DIRECTORY}; \ - /opt/code-server/install-vscode-extension https://github.com/felixfbecker/vscode-php-debug/releases/download/v${VSCODE_XDEBUG_VERSION}/php-debug.vsix felixfbecker.php-debug-${VSCODE_XDEBUG_VERSION}; \ - /opt/code-server/install-vscode-extension https://github.com/eamodio/vscode-gitlens/releases/download/v${VSCODE_GITLENS_VERSION}/gitlens-${VSCODE_GITLENS_VERSION}.vsix eamodio.gitlens-${VSCODE_GITLENS_VERSION} +# Note: Have to use --user-data-dir with --install-extension instead of --config +RUN set -xe; \ + code-server --user-data-dir=${VSCODE_HOME} --install-extension eamodio.gitlens@11.6.0; \ + code-server --user-data-dir=${VSCODE_HOME} --install-extension felixfbecker.php-debug@1.16.1 # Switch back to root (IMPORTANT!) USER root diff --git a/7.3/Makefile b/7.3/Makefile index aecb18ba..8920b684 100644 --- a/7.3/Makefile +++ b/7.3/Makefile @@ -1,42 +1,51 @@ -include ../tests/env_make -include env_make +IMAGE ?= docksal/cli +VERSION_PREFIX ?= php VERSION ?= 7.3 - -SOFTWARE_VERSION ?= php$(VERSION) -BUILD_TAG = build-$(SOFTWARE_VERSION) -REPO = docksal/cli -NAME = docksal-cli-$(VERSION) +BUILD_IMAGE_TAG ?= $(IMAGE):$(VERSION_PREFIX)$(VERSION)-build +NAME = docksal-cli-$(VERSION)-$(GIT_SHA7) CWD = $(shell pwd) # Improve write performance for /home/docker by turning it into a volume -VOLUMES += -v /home/docker +VOLUMES = -v /home/docker .EXPORT_ALL_VARIABLES: .PHONY: build test push shell run start stop logs clean release build: - docker build -t $(REPO):$(BUILD_TAG) . + docker build -t $(BUILD_IMAGE_TAG) . # See https://docs.docker.com/buildx/working-with-buildx/ # See https://github.com/docker/buildx buildx: - docker buildx build --tag $(REPO):$(BUILD_TAG) . + docker buildx build --tag $(BUILD_IMAGE_TAG) . buildx-with-cache: - docker buildx build --cache-from=type=registry,ref=ghcr.io/$(REPO):$(BUILD_TAG) --cache-to=type=inline --tag=$(REPO):$(BUILD_TAG) . + docker buildx build --cache-from=type=registry,ref=ghcr.io/$(BUILD_IMAGE_TAG) --cache-to=type=inline --tag=$(BUILD_IMAGE_TAG) . test: - IMAGE=$(REPO):$(BUILD_TAG) NAME=$(NAME) VERSION=$(VERSION) ../tests/test.bats + NAME=$(NAME) VERSION=$(VERSION) ../tests/test.bats push: - docker push $(REPO):$(BUILD_TAG) + docker push $(BUILD_IMAGE_TAG) run: clean - docker run --rm --name $(NAME) -it $(PORTS) $(VOLUMES) $(ENV) $(REPO):$(BUILD_TAG) + docker run --rm --name $(NAME) -it $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) +# Copy files into container instead of mounting from the host at runtime. +# This allows running tests on a remote docker instance. start: clean - docker run -d --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(REPO):$(BUILD_TAG) + docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) + docker cp ../tests/. $(NAME):/var/www/ + docker start $(NAME) + +# Only copy docroot (not config overrides) +start-bare: clean + docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) + docker cp ../tests/docroot/. $(NAME):/var/www/docroot/ + docker start $(NAME) # Non-interactive and non-tty docker exec (uses LF instead of CRLF line endings) exec: diff --git a/7.4/opt/code-server/settings.json b/7.3/config/code-server/User/settings.json similarity index 94% rename from 7.4/opt/code-server/settings.json rename to 7.3/config/code-server/User/settings.json index a1b14cbd..1007d613 100644 --- a/7.4/opt/code-server/settings.json +++ b/7.3/config/code-server/User/settings.json @@ -32,5 +32,6 @@ "*.tpl.php": "php", "*.test": "php", "*.php": "php" - } + }, + "workbench.colorTheme": "Default Dark+" } diff --git a/7.3/config/code-server/config.yaml.tmpl b/7.3/config/code-server/config.yaml.tmpl new file mode 100644 index 00000000..495d812e --- /dev/null +++ b/7.3/config/code-server/config.yaml.tmpl @@ -0,0 +1,9 @@ +user-data-dir: {{ getenv "VSCODE_HOME" }} +bind-addr: 0.0.0.0:8080 +cert: false +{{ if (getenv "IDE_PASSWORD") }} +auth: password +password: {{ getenv "IDE_PASSWORD" }} +{{ else }} +auth: none +{{ end }} diff --git a/7.3/config/php/xdebug.ini b/7.3/config/php/xdebug.ini index 65b25748..90111271 100644 --- a/7.3/config/php/xdebug.ini +++ b/7.3/config/php/xdebug.ini @@ -1,9 +1,12 @@ [xdebug] zend_extension=xdebug.so -xdebug.remote_enable=1 -xdebug.remote_autostart=1 -; xdebug.xdebug.remote_host defaults to "localhost", which works with VS Code Server web IDE -; For debugging from the host machine, xdebug.xdebug.remote_host is set to ${DOCKSAL_HOST_IP} at runtime -; xdebug.xdebug.remote_port is set at runtime: 9000 (default) +; See https://xdebug.org/docs/all_settings#mode +xdebug.mode=debug +; xdebug.xdebug.client_host defaults to "localhost", which works with VS Code Server web IDE running locally +; For debugging from a "remote" host, xdebug.xdebug.client_host is set to ${DOCKSAL_HOST_IP} at runtime +; xdebug.xdebug.client_port defaults to "9003" in Xdebug 3. We use 9000 instead for backward compatibility with Xdebug 2. +xdebug.client_port=9000 +; TODO: Why do we have to set this? xdebug.idekey=xdebug_session +; Increase max_nesting_level to support complex Drupal pages (default is 100) xdebug.max_nesting_level=256 diff --git a/7.3/config/supervisor/supervisord-code-server.conf.tmpl b/7.3/config/supervisor/supervisord-code-server.conf.tmpl index 30f5cc9a..7016f1a7 100644 --- a/7.3/config/supervisor/supervisord-code-server.conf.tmpl +++ b/7.3/config/supervisor/supervisord-code-server.conf.tmpl @@ -1,6 +1,6 @@ # VS Code Server web IDE [program:code-server] # Using bash -lc here to load docker user profile (necessary for nvn/node to initialize) -command = gosu docker bash -lc '/usr/bin/code-server --user-data-dir=/home/docker/code-server --disable-telemetry --bind-addr 0.0.0.0:8080 {{ if not (getenv "PASSWORD") }}--auth none{{ end }} /var/www' +command = gosu docker bash -lc '/usr/bin/code-server --config=${VSCODE_HOME}/config.yaml /var/www' stdout_logfile = /var/log/supervisor/code-server-stdout stderr_logfile = /var/log/supervisor/code-server-stderr diff --git a/7.3/healthcheck.sh b/7.3/healthcheck.sh index d1223772..b4ab59d0 100755 --- a/7.3/healthcheck.sh +++ b/7.3/healthcheck.sh @@ -1,19 +1,16 @@ #!/usr/bin/env bash -set -e # Exit on errors - # Initialization phase in startup.sh is complete -# Need to do "|| exit 1" here since "set -e" apparently does not care about tests. [[ -f /var/run/cli ]] || exit 1 # supervisor services are running if [[ -f /run/supervisord.pid ]]; then - if [[ "${IDE_ENABLED}" != "1" ]]; then + if [[ "${IDE_ENABLED}" == "1" ]]; then + # IDE mode + ps aux | grep code-server >/dev/null || exit 1 + else # php-fpm/cli mode [[ -f /run/php-fpm.pid ]] || exit 1 [[ -f /run/sshd.pid ]] || exit 1 - else - # IDE mode - ps aux | grep code-server >/dev/null fi fi diff --git a/7.3/opt/code-server/install-vscode-extension b/7.3/opt/code-server/install-vscode-extension deleted file mode 100755 index e50b208e..00000000 --- a/7.3/opt/code-server/install-vscode-extension +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -PLUGIN_URL=$1 -PLUGIN_DIRECTORY=$2 - -curl -fsSL "${PLUGIN_URL}" -o /tmp/extension.zip -unzip -qq /tmp/extension.zip -d /tmp/extension -mv /tmp/extension/extension ${VSCODE_EXT_DIRECTORY}/${PLUGIN_DIRECTORY} -rm -rf /tmp/extension.zip /tmp/extension diff --git a/7.3/php-modules.txt b/7.3/php-modules.txt deleted file mode 100644 index d2df798c..00000000 --- a/7.3/php-modules.txt +++ /dev/null @@ -1,68 +0,0 @@ -[PHP Modules] -apcu -bcmath -blackfire -bz2 -calendar -Core -ctype -curl -date -dom -exif -fileinfo -filter -ftp -gd -gettext -gnupg -hash -iconv -imagick -imap -intl -json -ldap -libxml -mbstring -memcached -mysqli -mysqlnd -openssl -pcntl -pcre -PDO -pdo_mysql -pdo_pgsql -pdo_sqlite -pdo_sqlsrv -pgsql -Phar -posix -readline -redis -Reflection -session -SimpleXML -soap -sockets -sodium -SPL -sqlite3 -sqlsrv -ssh2 -standard -sysvsem -tokenizer -xml -xmlreader -xmlwriter -xsl -Zend OPcache -zip -zlib - -[Zend Modules] -Zend OPcache -blackfire - diff --git a/7.3/startup.sh b/7.3/startup.sh index 11a34199..6bd0bf22 100755 --- a/7.3/startup.sh +++ b/7.3/startup.sh @@ -40,18 +40,20 @@ xhprof_enable () chown docker:docker ${XHPROF_OUTPUT_DIR} } +opcache_preload_enable() +{ + echo-debug "Enabling opcache preload..." + ln -s /opt/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/ +} + ide_mode_enable () { echo-debug "Enabling web IDE..." # Enabled only code-server service (disabled all other services) - # TODO: [v3] split IDE/cli and php-fpm entirely + # TODO: split IDE/cli and php-fpm entirely rm -f /etc/supervisor/conf.d/supervisord-*.conf - if [[ "$IDE_PASSWORD" != "" ]]; then - export PASSWORD="${IDE_PASSWORD}" - fi render_tmpl "/etc/supervisor/conf.d/supervisord-code-server.conf" - mkdir -p ${VSCODE_HOME}/User - ln -s /opt/code-server/settings.json ${VSCODE_HOME}/User/ + render_tmpl "${VSCODE_HOME}/config.yaml" } # Creates symlinks to project level overrides if they exist diff --git a/7.3/tests/essential-binaries.sh b/7.3/tests/essential-binaries.sh new file mode 100755 index 00000000..cdea93df --- /dev/null +++ b/7.3/tests/essential-binaries.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +binaries_amd64=\ +'cat +convert +curl +dig +g++ +ghostscript +git +git-lfs +gcc +jq +html2text +less +make +mc +more +mysql +nano +nslookup +ping +psql +pv +rsync +sudo +unzip +wget +yq +zip' + +binaries_arm64=\ +'cat +convert +curl +dig +g++ +ghostscript +git +git-lfs +gcc +html2text +less +make +mc +more +mysql +nano +nslookup +ping +psql +pv +rsync +sudo +unzip +wget +yq +zip' + +# Use the docker reported architecture and not the hosts (uname -m). +# docker arch may not be the same as hosts's arch (e.g., when using a remote docker instance). +case "$(docker info -f '{{ .Architecture }}')" in + x86_64) echo "${binaries_amd64}" ;; + amd64) echo "${binaries_amd64}" ;; + aarch64) echo "${binaries_arm64}" ;; + arm64) echo "${binaries_arm64}" ;; + * ) false;; +esac diff --git a/7.3/tests/php-modules.sh b/7.3/tests/php-modules.sh new file mode 100755 index 00000000..8037c6d1 --- /dev/null +++ b/7.3/tests/php-modules.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash + +php_modules_amd64=\ +'[PHP Modules] +apcu +bcmath +blackfire +bz2 +calendar +Core +ctype +curl +date +dom +exif +fileinfo +filter +ftp +gd +gettext +gnupg +hash +iconv +imagick +imap +intl +json +ldap +libxml +mbstring +memcached +mysqli +mysqlnd +openssl +pcntl +pcre +PDO +pdo_mysql +pdo_pgsql +pdo_sqlite +pdo_sqlsrv +pgsql +Phar +posix +readline +redis +Reflection +session +SimpleXML +soap +sockets +sodium +SPL +sqlite3 +sqlsrv +ssh2 +standard +sysvsem +tokenizer +xml +xmlreader +xmlwriter +xsl +Zend OPcache +zip +zlib + +[Zend Modules] +Zend OPcache +blackfire +' + +php_modules_arm64=\ +'[PHP Modules] +apcu +bcmath +blackfire +bz2 +calendar +Core +ctype +curl +date +dom +exif +fileinfo +filter +ftp +gd +gettext +gnupg +hash +iconv +imagick +imap +intl +json +ldap +libxml +mbstring +memcached +mysqli +mysqlnd +openssl +pcntl +pcre +PDO +pdo_mysql +pdo_pgsql +pdo_sqlite +pgsql +Phar +posix +readline +redis +Reflection +session +SimpleXML +soap +sockets +sodium +SPL +sqlite3 +ssh2 +standard +sysvsem +tokenizer +xml +xmlreader +xmlwriter +xsl +Zend OPcache +zip +zlib + +[Zend Modules] +Zend OPcache +blackfire +' + +# Use the docker reported architecture and not the hosts (uname -m). +# docker arch may not be the same as hosts's arch (e.g., when using a remote docker instance). +case "$(docker info -f '{{ .Architecture }}')" in + x86_64) echo "${php_modules_amd64}" ;; + amd64) echo "${php_modules_amd64}" ;; + aarch64) echo "${php_modules_arm64}" ;; + arm64) echo "${php_modules_arm64}" ;; + * ) false;; +esac diff --git a/7.4/.dockerignore b/7.4/.dockerignore index 69e0091b..0123c988 100644 --- a/7.4/.dockerignore +++ b/7.4/.dockerignore @@ -1,4 +1,4 @@ +tests .dockerignore Dockerfile Makefile -php-modules.txt diff --git a/7.4/Dockerfile b/7.4/Dockerfile index 5978b7fc..da02c2f9 100644 --- a/7.4/Dockerfile +++ b/7.4/Dockerfile @@ -1,5 +1,6 @@ FROM php:7.4-fpm-buster as cli +ARG TARGETARCH ARG DEBIAN_FRONTEND=noninteractive ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 @@ -35,10 +36,7 @@ RUN set -xe; \ echo "deb https://packages.blackfire.io/debian any main" | tee /etc/apt/sources.list.d/blackfire.list; \ # git-lfs repo curl -fsSL https://packagecloud.io/github/git-lfs/gpgkey | apt-key add -; \ - echo 'deb https://packagecloud.io/github/git-lfs/debian buster main' | tee /etc/apt/sources.list.d/github_git-lfs.list; \ - # MSQSQL repo - msodbcsql17, pecl/sqlsrv and pecl/pdo_sqlsrv (PHP 7.0+ only) - curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | apt-key add -; \ - echo 'deb https://packages.microsoft.com/debian/10/prod buster main' | tee /etc/apt/sources.list.d/mssql.list; + echo 'deb https://packagecloud.io/github/git-lfs/debian buster main' | tee /etc/apt/sources.list.d/github_git-lfs.list; # Additional packages RUN set -xe; \ @@ -87,16 +85,16 @@ RUN set -xe; \ echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers ENV GOSU_VERSION=1.12 \ - GOMPLATE_VERSION=3.8.0 + GOMPLATE_VERSION=3.9.0 RUN set -xe; \ # Install gosu and give access to the docker user primary group to use it. # gosu is used instead of sudo to start the main container process (pid 1) in a docker friendly way. # https://github.com/tianon/gosu - curl -fsSL "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-$(dpkg --print-architecture)" -o /usr/local/bin/gosu; \ - chown root:"$(id -gn docker)" /usr/local/bin/gosu; \ + curl -fsSL https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${TARGETARCH} -o /usr/local/bin/gosu; \ + chown root:$(id -gn docker) /usr/local/bin/gosu; \ chmod +sx /usr/local/bin/gosu; \ # gomplate (to process configuration templates in startup.sh) - curl -fsSL https://github.com/hairyhenderson/gomplate/releases/download/v${GOMPLATE_VERSION}/gomplate_linux-amd64-slim -o /usr/local/bin/gomplate; \ + curl -fsSL https://github.com/hairyhenderson/gomplate/releases/download/v${GOMPLATE_VERSION}/gomplate_linux-${TARGETARCH} -o /usr/local/bin/gomplate; \ chmod +x /usr/local/bin/gomplate # Configure sshd (for use PHPStorm's remote interpreters and tools integrations) @@ -136,8 +134,6 @@ RUN set -xe; \ unixodbc-dev \ "; \ apt-get update >/dev/null; \ - # Necessary for msodbcsql17 (MSSQL) - ACCEPT_EULA=Y \ apt-get -y --no-install-recommends install >/dev/null \ $buildDeps \ blackfire-php \ @@ -158,11 +154,7 @@ RUN set -xe; \ libxpm4 \ libxslt1.1 \ libzip4 \ - msodbcsql17 \ ;\ - # SSH2 must be installed from source for PHP 7.x - git clone https://github.com/php/pecl-networking-ssh2.git /usr/src/php/ext/ssh2 && rm -rf /usr/src/php/ext/ssh2/.git; \ - \ # --with-png-dir has been removed in PHP 7.4. libpng is required docker-php-ext-configure >/dev/null gd \ --with-freetype \ @@ -170,7 +162,8 @@ RUN set -xe; \ --with-webp \ --with-xpm; \ PHP_OPENSSL=yes docker-php-ext-configure >/dev/null imap --with-kerberos --with-imap-ssl; \ - docker-php-ext-configure >/dev/null ldap --with-libdir=lib/x86_64-linux-gnu/; \ + # Using $(uname -m) (returns x86_64 / aarch64) vs ${TARGETARCH} (returns amd64 / arm64) + docker-php-ext-configure >/dev/null ldap --with-libdir=lib/$(uname -m)-linux-gnu/; \ docker-php-ext-configure >/dev/null pgsql --with-pgsql=/usr/local/pgsql/; \ docker-php-ext-configure >/dev/null zip; \ \ @@ -192,7 +185,6 @@ RUN set -xe; \ pgsql \ soap \ sockets \ - ssh2 \ xsl \ zip \ sysvsem \ @@ -204,9 +196,8 @@ RUN set -xe; \ imagick \ # Use memcached (not memcache) for PHP 7.x memcached \ - pdo_sqlsrv \ redis \ - sqlsrv \ + ssh2-beta \ xdebug \ xhprof \ ;\ @@ -215,9 +206,8 @@ RUN set -xe; \ gnupg \ imagick \ memcached \ - pdo_sqlsrv \ redis \ - sqlsrv \ + ssh2 \ ;\ # Cleanup docker-php-source delete; \ @@ -225,20 +215,52 @@ RUN set -xe; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $buildDeps >/dev/null; \ apt-get clean; rm -rf /var/lib/apt/lists/* +# Packages not available for arm64 +RUN set -xe; \ + if [ "${TARGETARCH}" = "amd64" ]; then \ + # MSQSQL repo - msodbcsql17, pecl/sqlsrv and pecl/pdo_sqlsrv (PHP 7.0+ only) + curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | apt-key add -; \ + echo 'deb https://packages.microsoft.com/debian/10/prod buster main' | tee /etc/apt/sources.list.d/mssql.list; \ + \ + buildDeps=" \ + unixodbc-dev \ + "; \ + apt-get update >/dev/null; \ + # Necessary for msodbcsql17 (MSSQL) + ACCEPT_EULA=Y \ + apt-get -y --no-install-recommends install >/dev/null \ + $buildDeps \ + msodbcsql17 \ + ;\ + pecl update-channels; \ + pecl install >/dev/null /dev/null; \ + apt-get clean; rm -rf /var/lib/apt/lists/*; \ + fi + # PHP tools (installed globally) ENV COMPOSER_DEFAULT_VERSION=2 \ - COMPOSER_VERSION=1.10.19 \ - COMPOSER2_VERSION=2.0.8 \ - DRUSH_VERSION=8.4.5 \ - DRUSH_LAUNCHER_VERSION=0.8.0 \ + COMPOSER_VERSION=1.10.22 \ + COMPOSER2_VERSION=2.1.5 \ + DRUSH_VERSION=8.4.8 \ + DRUSH_LAUNCHER_VERSION=0.9.1 \ DRUPAL_CONSOLE_LAUNCHER_VERSION=1.9.7 \ - WPCLI_VERSION=2.4.0 \ - BLACKFIRE_VERSION=1.44.1 \ - PLATFORMSH_CLI_VERSION=3.63.3 \ - ACQUIA_CLI_VERSION=1.3.0 \ - TERMINUS_VERSION=2.4.1 \ + WPCLI_VERSION=2.5.0 \ + BLACKFIRE_VERSION=1.49.3 \ + PLATFORMSH_CLI_VERSION=3.66.0 \ + ACQUIA_CLI_VERSION=1.13.1 \ + TERMINUS_VERSION=2.6.0 \ JQ_VERSION=1.6 \ - YQ_VERSION=3.4.1 + YQ_VERSION=4.11.2 RUN set -xe; \ # Composer 1.x curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER_VERSION}/composer.phar" -o /usr/local/bin/composer1; \ @@ -253,38 +275,58 @@ RUN set -xe; \ # Wordpress CLI curl -fsSL "https://github.com/wp-cli/wp-cli/releases/download/v${WPCLI_VERSION}/wp-cli-${WPCLI_VERSION}.phar" -o /usr/local/bin/wp; \ # Blackfire CLI - curl -fsSL "https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_VERSION}/blackfire-cli-linux_static_amd64" -o /usr/local/bin/blackfire; \ + curl -fsSL "https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_VERSION}/blackfire-cli-linux_${TARGETARCH}" -o /usr/local/bin/blackfire; \ # Platform.sh CLI curl -fsSL "https://github.com/platformsh/platformsh-cli/releases/download/v${PLATFORMSH_CLI_VERSION}/platform.phar" -o /usr/local/bin/platform; \ # Acquia CLI curl -fsSL "https://github.com/acquia/cli/releases/download/${ACQUIA_CLI_VERSION}/acli.phar" -o /usr/local/bin/acli; \ # Pantheon Terminus curl -fsSL "https://github.com/pantheon-systems/terminus/releases/download/${TERMINUS_VERSION}/terminus.phar" -o /usr/local/bin/terminus; \ - # jq - curl -fsSL "https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64" -o /usr/local/bin/jq; \ + # jq (no arm64) + if [ "${TARGETARCH}" = "amd64" ]; then \ + curl -fsSL "https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64" -o /usr/local/bin/jq; \ + chmod +x /usr/local/bin/jq; \ + fi; \ # yq - curl -fsSL "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64" -o /usr/local/bin/yq; \ + curl -fsSL "https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_${TARGETARCH}" -o /usr/local/bin/yq; \ # Set Default Composer Version ln -s /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer; \ # Make all downloaded binaries executable in one shot - (cd /usr/local/bin && chmod +x composer1 composer2 drush8 drush drupal wp blackfire platform acli terminus jq yq); + (cd /usr/local/bin && chmod +x composer1 composer2 drush8 drush drupal wp blackfire platform acli terminus yq); + +# Install Python3 from Debian repos +# This adds about 30MB to uncompressed image size. +# TODO: some other dependency in this image installs python2. Which one? +RUN set -xe; \ + apt-get update >/dev/null; \ + apt-get -y --no-install-recommends install >/dev/null \ + python3 \ + ;\ + # Cleanup + apt-get clean; rm -rf /var/lib/apt/lists/* + +# Install Ruby from Debian repos +RUN set -xe; \ + apt-get update >/dev/null; \ + apt-get -y --no-install-recommends install >/dev/null \ + ruby-full \ + ;\ + # Cleanup + apt-get clean; rm -rf /var/lib/apt/lists/* # All further RUN commands will run as the "docker" user USER docker SHELL ["/bin/bash", "-c"] -# PHP tools (installed as user) -# Note: DRUSH_BACKDROP_VERSION should be pinned at 1.2.0 as 1.3.0 introduces changes that break regular drush 8. -ENV \ - MG_CODEGEN_VERSION=1.11.2 \ - DRUSH_BACKDROP_VERSION=1.2.0 # Don't use -x here, as the output may be excessive RUN set -e; \ \ # Set drush8 as a global fallback for Drush Launcher echo -e "\n""export DRUSH_LAUNCHER_FALLBACK=/usr/local/bin/drush8" >> $HOME/.profile; \ # Composer based dependencies - # Add composer bin directory to PATH + # Add composer bin project level and global directories to PATH + # Project level comes first and thus takes precedence over the global one + echo -e "\n"'export PATH="$PATH:${PROJECT_ROOT:-/var/www}/vendor/bin"' >> $HOME/.profile; \ echo -e "\n"'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> $HOME/.profile; \ # Reload updated PATH from profile to make composer/drush/etc. visible below . $HOME/.profile; \ @@ -297,25 +339,13 @@ $HOME/.composer/vendor/wp-coding-standards/wpcs/,\ $HOME/.composer/vendor/phpcompatibility/php-compatibility/PHPCompatibility/,\ $HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp/PHPCompatibilityWP,\ $HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie/PHPCompatibilityParagonieRandomCompat; \ - # Install cgr to use it in-place of `composer global require` for misc globally installed cli tools. - # See https://pantheon.io/blog/fixing-composer-global-command - composer global require consolidation/cgr >/dev/null; \ - # Magento2 Code Generator - # Cannot be properly installed and used as a phar binary - # See https://github.com/staempfli/magento2-code-generator/issues/11 - cgr staempfli/magento2-code-generator:${MG_CODEGEN_VERSION} >/dev/null; \ # Cleanup - composer clear-cache; \ - \ - # Drush modules - drush dl registry_rebuild --default-major=7 --destination=$HOME/.drush >/dev/null; \ - mkdir $HOME/.drush/backdrop && curl -fsSL "https://github.com/backdrop-contrib/backdrop-drush-extension/archive/${DRUSH_BACKDROP_VERSION}.tar.gz" | tar xz -C $HOME/.drush/backdrop --strip-components 1; \ - drush cc drush + composer clear-cache # Node.js (installed as user) ENV \ - NVM_VERSION=0.37.2 \ - NODE_VERSION=14.15.1 \ + NVM_VERSION=0.38.0 \ + NODE_VERSION=14.17.3 \ YARN_VERSION=1.22.10 # Don't use -x here, as the output may be excessive RUN set -e; \ @@ -328,61 +358,79 @@ RUN set -e; \ export YARN_PROFILE="$HOME/.profile"; \ curl -fsSL https://yarnpkg.com/install.sh | bash -s -- --version ${YARN_VERSION} >/dev/null -# Ruby (installed as user) -ENV \ - RVM_VERSION_INSTALL=1.29.10 \ - RUBY_VERSION_INSTALL=2.7.2 -# Don't use -x here, as the output may be excessive -RUN set -e; \ - # Public GPG servers are not realiable, so downloading keys from rvm.io instead. - #gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB - # Import and trust rvm keys - # mpapis@gmail.com - curl -sSL https://rvm.io/mpapis.asc | gpg --batch --import -; \ - echo 409B6B1796C275462A1703113804BB82D39DC0E3:6: | gpg --batch --import-ownertrust; \ - # piotr.kuczynski@gmail.com - curl -sSL https://rvm.io/pkuczynski.asc | gpg --batch --import -; \ - echo 7D2BAF1CF37B13E2069D6956105BD0E739499BDB:6: | gpg --batch --import-ownertrust; \ - \ - echo 'rvm_autoupdate_flag=0' >> $HOME/.rvmrc; \ - echo 'rvm_silence_path_mismatch_check_flag=1' >> $HOME/.rvmrc; \ - curl -fsSL https://raw.githubusercontent.com/rvm/rvm/${RVM_VERSION_INSTALL}/binscripts/rvm-installer | bash -s -- --ignore-dotfiles --version ${RVM_VERSION_INSTALL}; \ - { \ - echo ''; \ - echo 'export PATH="$PATH:$HOME/.rvm/bin"'; \ - echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"'; \ - } >> $HOME/.profile; \ - # Reload $HOME/.profile to apply settings for the current shell - . $HOME/.profile; \ - \ - # rvm.io does not currently have ruby binaries for Debian 9, so Ruby is compiled from source, which requires a bunch - # of extra dependencies installed (rvm installs these automatically), which bloat this image: - # rvm/ruby required packages: gawk, automake, bison, libffi-dev, libgdbm-dev, libncurses5-dev, libsqlite3-dev, libtool, libyaml-dev, sqlite3, zlib1g-dev, libgmp-dev, libreadline-dev, libssl-dev - rvm install ruby-${RUBY_VERSION_INSTALL}; \ - rvm use ruby-${RUBY_VERSION_INSTALL} --default; \ - \ - gem install bundler; \ - # Have bundler install gems locally (./.bundle) by default - echo -e "\n"'export BUNDLE_PATH=.bundle' >> $HOME/.profile; \ - \ - rvm cleanup all; \ - rvm gemset globalcache enable - -# Python (installed as user) -ENV \ - PYENV_VERSION_INSTALL=1.2.21 +## Ruby (installed as user) via rvm +## Note: Disabled. rvm + its build dependecies bloat the image (~80MB) +## Debian 10 ships with Ruby 2.5, so we'll stick with that by default. +## It is still possible for the end user to switch to a different Ruby version via rvm. +#ENV \ +# RVM_VERSION_INSTALL=1.29.10 \ +# RUBY_VERSION_INSTALL=2.7.2 +## Don't use -x here, as the output may be excessive +#RUN set -e; \ +# # Export ruby gem bin path +# echo 'export PATH=$PATH:$(ruby -r rubygems -e "puts Gem.user_dir")/bin' >> $HOME/.profile; \ +# . $HOME/.profile; \ +# # Public GPG servers are not realiable, so downloading keys from rvm.io instead. +# #gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB +# # Import and trust rvm keys +# # mpapis@gmail.com +# curl -sSL https://rvm.io/mpapis.asc | gpg --batch --import -; \ +# echo 409B6B1796C275462A1703113804BB82D39DC0E3:6: | gpg --batch --import-ownertrust; \ +# # piotr.kuczynski@gmail.com +# curl -sSL https://rvm.io/pkuczynski.asc | gpg --batch --import -; \ +# echo 7D2BAF1CF37B13E2069D6956105BD0E739499BDB:6: | gpg --batch --import-ownertrust; \ +# \ +# echo 'rvm_autoupdate_flag=0' >> $HOME/.rvmrc; \ +# echo 'rvm_silence_path_mismatch_check_flag=1' >> $HOME/.rvmrc; \ +# curl -fsSL https://raw.githubusercontent.com/rvm/rvm/${RVM_VERSION_INSTALL}/binscripts/rvm-installer | bash -s -- --ignore-dotfiles --version ${RVM_VERSION_INSTALL}; \ +# { \ +# echo ''; \ +# echo 'export PATH="$PATH:$HOME/.rvm/bin"'; \ +# echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"'; \ +# } >> $HOME/.profile; \ +# # Reload $HOME/.profile to apply settings for the current shell +# . $HOME/.profile; \ +# \ +# # rvm.io does not currently have ruby binaries for Debian 9, so Ruby is compiled from source, which requires a bunch +# # of extra dependencies installed (rvm installs these automatically), which bloat this image: +# # rvm/ruby required packages: gawk, automake, bison, libffi-dev, libgdbm-dev, libncurses5-dev, libsqlite3-dev, libtool, libyaml-dev, sqlite3, zlib1g-dev, libgmp-dev, libreadline-dev, libssl-dev +# rvm install ruby-${RUBY_VERSION_INSTALL}; \ +# rvm use ruby-${RUBY_VERSION_INSTALL} --default; \ +# \ +# gem install --user-install bundler; \ +# # Have bundler install gems locally (./.bundle) by default +# echo -e "\n"'export BUNDLE_PATH=.bundle' >> $HOME/.profile; \ +# \ +# rvm cleanup all; \ +# rvm gemset globalcache enable + +# Python (installed as user) via pyenv +# Note: Disabled. pyenv + its build dependecies bloat the image (~300MB). +# Debian 10 ships with Python 3.7, so we'll stick with that by default. +# It is still possible for the end user to switch to a different python version via pyenv. +#ENV \ +# PYENV_VERSION_INSTALL=1.2.21 \ # PYTHON_VERSION_INSTALL=3.8.3 -RUN set -xe; \ - git clone --depth 1 -b v${PYENV_VERSION_INSTALL} https://github.com/pyenv/pyenv.git $HOME/.pyenv; \ - rm -rf $HOME/.pyenv/.git; \ - { \ - echo ''; \ - echo 'export PYENV_ROOT="$HOME/.pyenv"'; \ - echo 'export PATH="$PYENV_ROOT/bin:$PATH"'; \ - echo 'eval "$(pyenv init -)"'; \ - } >> $HOME/.profile -# Disabled for now - uses too much space (~200MB). -# The upsteam Debian 9 image ships with Python 2.7 out of the box, so we'll stick with that by default. +#RUN set -xe; \ +# # pyenv requires a bunch of build dependencies installed, which would bloat this image +# # See https://github.com/pyenv/pyenv/wiki/Common-build-problems#prerequisites +# sudo apt-get update >/dev/null; \ +# sudo apt-get -y --no-install-recommends install >/dev/null \ +# build-essential libssl-dev zlib1g-dev libbz2-dev \ +# libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \ +# xz-utils tk-dev libffi-dev liblzma-dev python-openssl git \ +# ;\ +# # Cleanup +# sudo apt-get clean; sudo rm -rf /var/lib/apt/lists/*; \ +# \ +# git clone --depth 1 -b v${PYENV_VERSION_INSTALL} https://github.com/pyenv/pyenv.git $HOME/.pyenv; \ +# rm -rf $HOME/.pyenv/.git; \ +# { \ +# echo ''; \ +# echo 'export PYENV_ROOT="$HOME/.pyenv"'; \ +# echo 'export PATH="$PYENV_ROOT/bin:$PATH"'; \ +# echo 'eval "$(pyenv init -)"'; \ +# } >> $HOME/.profile; \ # # Reload $HOME/.profile to apply settings for the current shell # . $HOME/.profile; \ # pyenv install ${PYTHON_VERSION_INSTALL}; \ @@ -454,28 +502,25 @@ USER docker ARG HOME=/home/docker ENV \ - CODE_SERVER_VERSION=3.7.4 \ - VSCODE_HOME="${HOME}/code-server" \ - VSCODE_EXT_DIRECTORY="${HOME}/code-server/extensions" \ - VSCODE_XDEBUG_VERSION=1.13.0 \ - VSCODE_GITLENS_VERSION=11.0.6 + CODE_SERVER_VERSION=3.11.0 \ + VSCODE_XDEBUG_VERSION=1.16.1 \ + VSCODE_GITLENS_VERSION=11.6.0 \ + VSCODE_HOME="${HOME}/code-server" # Install code-server -RUN \ - set -xe; \ - curl -fsSL "https://github.com/cdr/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server_${CODE_SERVER_VERSION}_amd64.deb" -o /tmp/code-server_amd64.deb; \ - sudo dpkg -i /tmp/code-server_amd64.deb; \ +RUN set -xe; \ + curl -fsSL "https://github.com/cdr/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server_${CODE_SERVER_VERSION}_${TARGETARCH}.deb" -o /tmp/code-server_${TARGETARCH}.deb; \ + sudo dpkg -i /tmp/code-server_${TARGETARCH}.deb; \ rm -rf /tmp/*.* -# Settings and scripts -COPY --chown=docker:docker opt/code-server /opt/code-server +# Settings +COPY --chown=docker:docker config/code-server ${VSCODE_HOME} # Install extensions -RUN \ - set -xe; \ - mkdir -p ${VSCODE_EXT_DIRECTORY}; \ - /opt/code-server/install-vscode-extension https://github.com/felixfbecker/vscode-php-debug/releases/download/v${VSCODE_XDEBUG_VERSION}/php-debug.vsix felixfbecker.php-debug-${VSCODE_XDEBUG_VERSION}; \ - /opt/code-server/install-vscode-extension https://github.com/eamodio/vscode-gitlens/releases/download/v${VSCODE_GITLENS_VERSION}/gitlens-${VSCODE_GITLENS_VERSION}.vsix eamodio.gitlens-${VSCODE_GITLENS_VERSION} +# Note: Have to use --user-data-dir with --install-extension instead of --config +RUN set -xe; \ + code-server --user-data-dir=${VSCODE_HOME} --install-extension eamodio.gitlens@11.6.0; \ + code-server --user-data-dir=${VSCODE_HOME} --install-extension felixfbecker.php-debug@1.16.1 # Switch back to root (IMPORTANT!) USER root diff --git a/7.4/Makefile b/7.4/Makefile index b13d689b..0296dcc7 100644 --- a/7.4/Makefile +++ b/7.4/Makefile @@ -1,42 +1,51 @@ -include ../tests/env_make -include env_make +IMAGE ?= docksal/cli +VERSION_PREFIX ?= php VERSION ?= 7.4 - -SOFTWARE_VERSION ?= php$(VERSION) -BUILD_TAG = build-$(SOFTWARE_VERSION) -REPO = docksal/cli -NAME = docksal-cli-$(VERSION) +BUILD_IMAGE_TAG ?= $(IMAGE):$(VERSION_PREFIX)$(VERSION)-build +NAME = docksal-cli-$(VERSION)-$(GIT_SHA7) CWD = $(shell pwd) # Improve write performance for /home/docker by turning it into a volume -VOLUMES += -v /home/docker +VOLUMES = -v /home/docker .EXPORT_ALL_VARIABLES: .PHONY: build test push shell run start stop logs clean release build: - docker build -t $(REPO):$(BUILD_TAG) . + docker build -t $(BUILD_IMAGE_TAG) . # See https://docs.docker.com/buildx/working-with-buildx/ # See https://github.com/docker/buildx buildx: - docker buildx build --tag $(REPO):$(BUILD_TAG) . + docker buildx build --tag $(BUILD_IMAGE_TAG) . buildx-with-cache: - docker buildx build --cache-from=type=registry,ref=ghcr.io/$(REPO):$(BUILD_TAG) --cache-to=type=inline --tag=$(REPO):$(BUILD_TAG) . + docker buildx build --cache-from=type=registry,ref=ghcr.io/$(BUILD_IMAGE_TAG) --cache-to=type=inline --tag=$(BUILD_IMAGE_TAG) . test: - IMAGE=$(REPO):$(BUILD_TAG) NAME=$(NAME) VERSION=$(VERSION) ../tests/test.bats + NAME=$(NAME) VERSION=$(VERSION) ../tests/test.bats push: - docker push $(REPO):$(BUILD_TAG) + docker push $(BUILD_IMAGE_TAG) run: clean - docker run --rm --name $(NAME) -it $(PORTS) $(VOLUMES) $(ENV) $(REPO):$(BUILD_TAG) + docker run --rm --name $(NAME) -it $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) +# Copy files into container instead of mounting from the host at runtime. +# This allows running tests on a remote docker instance. start: clean - docker run -d --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(REPO):$(BUILD_TAG) + docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) + docker cp ../tests/. $(NAME):/var/www/ + docker start $(NAME) + +# Only copy docroot (not config overrides) +start-bare: clean + docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) + docker cp ../tests/docroot/. $(NAME):/var/www/docroot/ + docker start $(NAME) # Non-interactive and non-tty docker exec (uses LF instead of CRLF line endings) exec: diff --git a/7.3/opt/code-server/settings.json b/7.4/config/code-server/User/settings.json similarity index 94% rename from 7.3/opt/code-server/settings.json rename to 7.4/config/code-server/User/settings.json index a1b14cbd..1007d613 100644 --- a/7.3/opt/code-server/settings.json +++ b/7.4/config/code-server/User/settings.json @@ -32,5 +32,6 @@ "*.tpl.php": "php", "*.test": "php", "*.php": "php" - } + }, + "workbench.colorTheme": "Default Dark+" } diff --git a/7.4/config/code-server/config.yaml.tmpl b/7.4/config/code-server/config.yaml.tmpl new file mode 100644 index 00000000..495d812e --- /dev/null +++ b/7.4/config/code-server/config.yaml.tmpl @@ -0,0 +1,9 @@ +user-data-dir: {{ getenv "VSCODE_HOME" }} +bind-addr: 0.0.0.0:8080 +cert: false +{{ if (getenv "IDE_PASSWORD") }} +auth: password +password: {{ getenv "IDE_PASSWORD" }} +{{ else }} +auth: none +{{ end }} diff --git a/7.4/config/php/xdebug.ini b/7.4/config/php/xdebug.ini index 65b25748..90111271 100644 --- a/7.4/config/php/xdebug.ini +++ b/7.4/config/php/xdebug.ini @@ -1,9 +1,12 @@ [xdebug] zend_extension=xdebug.so -xdebug.remote_enable=1 -xdebug.remote_autostart=1 -; xdebug.xdebug.remote_host defaults to "localhost", which works with VS Code Server web IDE -; For debugging from the host machine, xdebug.xdebug.remote_host is set to ${DOCKSAL_HOST_IP} at runtime -; xdebug.xdebug.remote_port is set at runtime: 9000 (default) +; See https://xdebug.org/docs/all_settings#mode +xdebug.mode=debug +; xdebug.xdebug.client_host defaults to "localhost", which works with VS Code Server web IDE running locally +; For debugging from a "remote" host, xdebug.xdebug.client_host is set to ${DOCKSAL_HOST_IP} at runtime +; xdebug.xdebug.client_port defaults to "9003" in Xdebug 3. We use 9000 instead for backward compatibility with Xdebug 2. +xdebug.client_port=9000 +; TODO: Why do we have to set this? xdebug.idekey=xdebug_session +; Increase max_nesting_level to support complex Drupal pages (default is 100) xdebug.max_nesting_level=256 diff --git a/7.4/config/supervisor/supervisord-code-server.conf.tmpl b/7.4/config/supervisor/supervisord-code-server.conf.tmpl index 30f5cc9a..7016f1a7 100644 --- a/7.4/config/supervisor/supervisord-code-server.conf.tmpl +++ b/7.4/config/supervisor/supervisord-code-server.conf.tmpl @@ -1,6 +1,6 @@ # VS Code Server web IDE [program:code-server] # Using bash -lc here to load docker user profile (necessary for nvn/node to initialize) -command = gosu docker bash -lc '/usr/bin/code-server --user-data-dir=/home/docker/code-server --disable-telemetry --bind-addr 0.0.0.0:8080 {{ if not (getenv "PASSWORD") }}--auth none{{ end }} /var/www' +command = gosu docker bash -lc '/usr/bin/code-server --config=${VSCODE_HOME}/config.yaml /var/www' stdout_logfile = /var/log/supervisor/code-server-stdout stderr_logfile = /var/log/supervisor/code-server-stderr diff --git a/7.4/healthcheck.sh b/7.4/healthcheck.sh index d1223772..b4ab59d0 100755 --- a/7.4/healthcheck.sh +++ b/7.4/healthcheck.sh @@ -1,19 +1,16 @@ #!/usr/bin/env bash -set -e # Exit on errors - # Initialization phase in startup.sh is complete -# Need to do "|| exit 1" here since "set -e" apparently does not care about tests. [[ -f /var/run/cli ]] || exit 1 # supervisor services are running if [[ -f /run/supervisord.pid ]]; then - if [[ "${IDE_ENABLED}" != "1" ]]; then + if [[ "${IDE_ENABLED}" == "1" ]]; then + # IDE mode + ps aux | grep code-server >/dev/null || exit 1 + else # php-fpm/cli mode [[ -f /run/php-fpm.pid ]] || exit 1 [[ -f /run/sshd.pid ]] || exit 1 - else - # IDE mode - ps aux | grep code-server >/dev/null fi fi diff --git a/7.4/opt/code-server/install-vscode-extension b/7.4/opt/code-server/install-vscode-extension deleted file mode 100755 index e50b208e..00000000 --- a/7.4/opt/code-server/install-vscode-extension +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -PLUGIN_URL=$1 -PLUGIN_DIRECTORY=$2 - -curl -fsSL "${PLUGIN_URL}" -o /tmp/extension.zip -unzip -qq /tmp/extension.zip -d /tmp/extension -mv /tmp/extension/extension ${VSCODE_EXT_DIRECTORY}/${PLUGIN_DIRECTORY} -rm -rf /tmp/extension.zip /tmp/extension diff --git a/7.4/php-modules.txt b/7.4/php-modules.txt deleted file mode 100644 index d2df798c..00000000 --- a/7.4/php-modules.txt +++ /dev/null @@ -1,68 +0,0 @@ -[PHP Modules] -apcu -bcmath -blackfire -bz2 -calendar -Core -ctype -curl -date -dom -exif -fileinfo -filter -ftp -gd -gettext -gnupg -hash -iconv -imagick -imap -intl -json -ldap -libxml -mbstring -memcached -mysqli -mysqlnd -openssl -pcntl -pcre -PDO -pdo_mysql -pdo_pgsql -pdo_sqlite -pdo_sqlsrv -pgsql -Phar -posix -readline -redis -Reflection -session -SimpleXML -soap -sockets -sodium -SPL -sqlite3 -sqlsrv -ssh2 -standard -sysvsem -tokenizer -xml -xmlreader -xmlwriter -xsl -Zend OPcache -zip -zlib - -[Zend Modules] -Zend OPcache -blackfire - diff --git a/7.4/startup.sh b/7.4/startup.sh index 1b534963..11e2d082 100755 --- a/7.4/startup.sh +++ b/7.4/startup.sh @@ -42,22 +42,18 @@ xhprof_enable () opcache_preload_enable() { - echo-debug "Enabling opcache preload..." - ln -s /opt/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/ + echo-debug "Enabling opcache preload..." + ln -s /opt/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/ } ide_mode_enable () { echo-debug "Enabling web IDE..." # Enabled only code-server service (disabled all other services) - # TODO: [v3] split IDE/cli and php-fpm entirely + # TODO: split IDE/cli and php-fpm entirely rm -f /etc/supervisor/conf.d/supervisord-*.conf - if [[ "$IDE_PASSWORD" != "" ]]; then - export PASSWORD="${IDE_PASSWORD}" - fi render_tmpl "/etc/supervisor/conf.d/supervisord-code-server.conf" - mkdir -p ${VSCODE_HOME}/User - ln -s /opt/code-server/settings.json ${VSCODE_HOME}/User/ + render_tmpl "${VSCODE_HOME}/config.yaml" } # Creates symlinks to project level overrides if they exist diff --git a/7.4/tests/essential-binaries.sh b/7.4/tests/essential-binaries.sh new file mode 100755 index 00000000..cdea93df --- /dev/null +++ b/7.4/tests/essential-binaries.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +binaries_amd64=\ +'cat +convert +curl +dig +g++ +ghostscript +git +git-lfs +gcc +jq +html2text +less +make +mc +more +mysql +nano +nslookup +ping +psql +pv +rsync +sudo +unzip +wget +yq +zip' + +binaries_arm64=\ +'cat +convert +curl +dig +g++ +ghostscript +git +git-lfs +gcc +html2text +less +make +mc +more +mysql +nano +nslookup +ping +psql +pv +rsync +sudo +unzip +wget +yq +zip' + +# Use the docker reported architecture and not the hosts (uname -m). +# docker arch may not be the same as hosts's arch (e.g., when using a remote docker instance). +case "$(docker info -f '{{ .Architecture }}')" in + x86_64) echo "${binaries_amd64}" ;; + amd64) echo "${binaries_amd64}" ;; + aarch64) echo "${binaries_arm64}" ;; + arm64) echo "${binaries_arm64}" ;; + * ) false;; +esac diff --git a/7.4/tests/php-modules.sh b/7.4/tests/php-modules.sh new file mode 100755 index 00000000..8037c6d1 --- /dev/null +++ b/7.4/tests/php-modules.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash + +php_modules_amd64=\ +'[PHP Modules] +apcu +bcmath +blackfire +bz2 +calendar +Core +ctype +curl +date +dom +exif +fileinfo +filter +ftp +gd +gettext +gnupg +hash +iconv +imagick +imap +intl +json +ldap +libxml +mbstring +memcached +mysqli +mysqlnd +openssl +pcntl +pcre +PDO +pdo_mysql +pdo_pgsql +pdo_sqlite +pdo_sqlsrv +pgsql +Phar +posix +readline +redis +Reflection +session +SimpleXML +soap +sockets +sodium +SPL +sqlite3 +sqlsrv +ssh2 +standard +sysvsem +tokenizer +xml +xmlreader +xmlwriter +xsl +Zend OPcache +zip +zlib + +[Zend Modules] +Zend OPcache +blackfire +' + +php_modules_arm64=\ +'[PHP Modules] +apcu +bcmath +blackfire +bz2 +calendar +Core +ctype +curl +date +dom +exif +fileinfo +filter +ftp +gd +gettext +gnupg +hash +iconv +imagick +imap +intl +json +ldap +libxml +mbstring +memcached +mysqli +mysqlnd +openssl +pcntl +pcre +PDO +pdo_mysql +pdo_pgsql +pdo_sqlite +pgsql +Phar +posix +readline +redis +Reflection +session +SimpleXML +soap +sockets +sodium +SPL +sqlite3 +ssh2 +standard +sysvsem +tokenizer +xml +xmlreader +xmlwriter +xsl +Zend OPcache +zip +zlib + +[Zend Modules] +Zend OPcache +blackfire +' + +# Use the docker reported architecture and not the hosts (uname -m). +# docker arch may not be the same as hosts's arch (e.g., when using a remote docker instance). +case "$(docker info -f '{{ .Architecture }}')" in + x86_64) echo "${php_modules_amd64}" ;; + amd64) echo "${php_modules_amd64}" ;; + aarch64) echo "${php_modules_arm64}" ;; + arm64) echo "${php_modules_arm64}" ;; + * ) false;; +esac diff --git a/8.0/.dockerignore b/8.0/.dockerignore new file mode 100644 index 00000000..0123c988 --- /dev/null +++ b/8.0/.dockerignore @@ -0,0 +1,4 @@ +tests +.dockerignore +Dockerfile +Makefile diff --git a/8.0/Dockerfile b/8.0/Dockerfile new file mode 100644 index 00000000..a08e1e06 --- /dev/null +++ b/8.0/Dockerfile @@ -0,0 +1,524 @@ +FROM php:8.0-fpm-buster as cli + +ARG TARGETARCH +ARG DEBIAN_FRONTEND=noninteractive +ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 + +# Prevent services autoload (http://jpetazzo.github.io/2013/10/06/policy-rc-d-do-not-start-services-automatically/) +RUN set -xe; \ + echo '#!/bin/sh\nexit 101' > /usr/sbin/policy-rc.d && chmod +x /usr/sbin/policy-rc.d + +# Install basic packages +RUN set -xe; \ + apt-get update >/dev/null; \ + apt-get -y --no-install-recommends install >/dev/null \ + apt-transport-https \ + # ca-certificates and curl come from upstream + #ca-certificates \ + #curl \ + gnupg \ + locales \ + wget \ + ;\ + # Cleanup + apt-get clean; rm -rf /var/lib/apt/lists/* + +# Set en_US.UTF-8 as the default locale +RUN set -xe; \ + localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 +ENV LC_ALL en_US.utf8 + +# Enable additional repos +RUN set -xe; \ + sed -i 's/main/main contrib non-free/' /etc/apt/sources.list; \ + # blackfire.io repo + curl -fsSL https://packages.blackfire.io/gpg.key | apt-key add -; \ + echo "deb https://packages.blackfire.io/debian any main" | tee /etc/apt/sources.list.d/blackfire.list; \ + # git-lfs repo + curl -fsSL https://packagecloud.io/github/git-lfs/gpgkey | apt-key add -; \ + echo 'deb https://packagecloud.io/github/git-lfs/debian buster main' | tee /etc/apt/sources.list.d/github_git-lfs.list; + +# Additional packages +RUN set -xe; \ + # Create man direcotries, otherwise some packages may not install (e.g. postgresql-client) + # This should be a temporary workaround until fixed upstream: https://github.com/debuerreotype/debuerreotype/issues/10 + mkdir -p /usr/share/man/man1 /usr/share/man/man7; \ + apt-get update >/dev/null; \ + apt-get -y --no-install-recommends install >/dev/null \ + cron \ + dnsutils \ + git \ + git-lfs \ + ghostscript \ + # html2text binary - used for self-testing (php-fpm) + html2text \ + imagemagick \ + iputils-ping \ + less \ + # cgi-fcgi binary - used for self-testing (php-fpm) + libfcgi-bin \ + mc \ + msmtp \ + # Debian 10 ships with MariaDB instead of MySQL + mariadb-client \ + nano \ + openssh-client \ + openssh-server \ + postgresql-client \ + procps \ + pv \ + rsync \ + sudo \ + supervisor \ + unzip \ + webp \ + zip \ + ;\ + # Cleanup + apt-get clean; rm -rf /var/lib/apt/lists/* + +RUN set -xe; \ + # Create a regular user/group "docker" (uid = 1000, gid = 1000 ) + useradd -m -s /bin/bash -u 1000 -U -p docker docker; \ + # Give the docker user sudo access + usermod -a -G sudo docker; \ + echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +ENV GOSU_VERSION=1.12 \ + GOMPLATE_VERSION=3.9.0 +RUN set -xe; \ + # Install gosu and give access to the docker user primary group to use it. + # gosu is used instead of sudo to start the main container process (pid 1) in a docker friendly way. + # https://github.com/tianon/gosu + curl -fsSL https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${TARGETARCH} -o /usr/local/bin/gosu; \ + chown root:$(id -gn docker) /usr/local/bin/gosu; \ + chmod +sx /usr/local/bin/gosu; \ + # gomplate (to process configuration templates in startup.sh) + curl -fsSL https://github.com/hairyhenderson/gomplate/releases/download/v${GOMPLATE_VERSION}/gomplate_linux-${TARGETARCH} -o /usr/local/bin/gomplate; \ + chmod +x /usr/local/bin/gomplate + +# Configure sshd (for use PHPStorm's remote interpreters and tools integrations) +# http://docs.docker.com/examples/running_ssh_service/ +RUN set -xe; \ + mkdir /var/run/sshd; \ + echo 'docker:docker' | chpasswd; \ + sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config; \ + # SSH login fix. Otherwise user is kicked off after login + sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd; \ + echo "export VISIBLE=now" >> /etc/profile +ENV NOTVISIBLE "in users profile" + +# PHP +RUN set -xe; \ + # Note: essential build tools (g++, gcc, make, etc) are included upstream as persistent packages. + # See https://github.com/docker-library/php/blob/406fcd31e62d633f62ac0d7bc5fc29aa1b3929fc/7.2/buster/fpm/Dockerfile#L18-L40 + buildDeps=" \ + libc-client2007e-dev \ + libfreetype6-dev \ + libgpgme11-dev \ + libicu-dev \ + libjpeg62-turbo-dev \ + libkrb5-dev \ + libldap2-dev \ + libmagickcore-dev \ + libmagickwand-dev \ + libmemcached-dev \ + libmhash-dev \ + libpng-dev \ + libpq-dev \ + libwebp-dev \ + libssh2-1-dev \ + libxpm-dev \ + libxslt1-dev \ + libzip-dev \ + unixodbc-dev \ + "; \ + apt-get update >/dev/null; \ + apt-get -y --no-install-recommends install >/dev/null \ + $buildDeps \ + blackfire-php \ + libc-client2007e \ + libfreetype6 \ + libgpgme11 \ + libicu63 \ + libjpeg62-turbo \ + libldap-2.4-2 \ + libmagickcore-6.q16-*-extra \ + libmagickwand-6.q16-6 \ + libmemcached11 \ + libmemcachedutil2 \ + libmhash2 \ + libpng16-16 \ + libpq5 \ + libssh2-1 \ + libxpm4 \ + libxslt1.1 \ + libzip4 \ + ;\ + docker-php-ext-configure >/dev/null gd \ + --with-freetype \ + --with-jpeg \ + --with-webp \ + --with-xpm; \ + PHP_OPENSSL=yes docker-php-ext-configure >/dev/null imap --with-kerberos --with-imap-ssl; \ + # Using $(uname -m) (returns x86_64 / aarch64) vs ${TARGETARCH} (returns amd64 / arm64) + docker-php-ext-configure >/dev/null ldap --with-libdir=lib/$(uname -m)-linux-gnu/; \ + docker-php-ext-configure >/dev/null pgsql --with-pgsql=/usr/local/pgsql/; \ + docker-php-ext-configure >/dev/null zip; \ + \ + docker-php-ext-install >/dev/null -j$(nproc) \ + bcmath \ + bz2 \ + calendar\ + exif \ + gd \ + gettext \ + imap \ + intl \ + ldap \ + mysqli \ + opcache \ + pcntl \ + pdo_mysql \ + pdo_pgsql \ + pgsql \ + soap \ + sockets \ + xsl \ + zip \ + sysvsem \ + ;\ + pecl update-channels; \ + pecl install >/dev/null /dev/null; \ + apt-get clean; rm -rf /var/lib/apt/lists/* + +# Packages not available for arm64 +RUN set -xe; \ + if [ "${TARGETARCH}" = "amd64" ]; then \ + # MSQSQL repo - msodbcsql17, pecl/sqlsrv and pecl/pdo_sqlsrv (PHP 7.0+ only) + curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | apt-key add -; \ + echo 'deb https://packages.microsoft.com/debian/10/prod buster main' | tee /etc/apt/sources.list.d/mssql.list; \ + \ + buildDeps=" \ + unixodbc-dev \ + "; \ + apt-get update >/dev/null; \ + # Necessary for msodbcsql17 (MSSQL) + ACCEPT_EULA=Y \ + apt-get -y --no-install-recommends install >/dev/null \ + $buildDeps \ + msodbcsql17 \ + ;\ + pecl update-channels; \ + pecl install >/dev/null /dev/null; \ + apt-get clean; rm -rf /var/lib/apt/lists/*; \ + fi + +# PHP tools (installed globally) +ENV COMPOSER_DEFAULT_VERSION=2 \ + COMPOSER_VERSION=1.10.22 \ + COMPOSER2_VERSION=2.1.5 \ + DRUSH_VERSION=8.4.8 \ + DRUSH_LAUNCHER_VERSION=0.9.1 \ + DRUPAL_CONSOLE_LAUNCHER_VERSION=1.9.7 \ + WPCLI_VERSION=2.5.0 \ + BLACKFIRE_VERSION=1.49.3 \ + PLATFORMSH_CLI_VERSION=3.66.0 \ + ACQUIA_CLI_VERSION=1.13.1 \ + TERMINUS_VERSION=2.6.0 \ + JQ_VERSION=1.6 \ + YQ_VERSION=4.11.2 +RUN set -xe; \ + # Composer 1.x + curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER_VERSION}/composer.phar" -o /usr/local/bin/composer1; \ + # Composer 2.x + curl -fsSL "https://github.com/composer/composer/releases/download/${COMPOSER2_VERSION}/composer.phar" -o /usr/local/bin/composer2; \ + # Drush 8 (global fallback) + curl -fsSL "https://github.com/drush-ops/drush/releases/download/${DRUSH_VERSION}/drush.phar" -o /usr/local/bin/drush8; \ + # Drush Launcher + curl -fsSL "https://github.com/drush-ops/drush-launcher/releases/download/${DRUSH_LAUNCHER_VERSION}/drush.phar" -o /usr/local/bin/drush; \ + # Drupal Console Launcher + curl -fsSL "https://github.com/hechoendrupal/drupal-console-launcher/releases/download/${DRUPAL_CONSOLE_LAUNCHER_VERSION}/drupal.phar" -o /usr/local/bin/drupal; \ + # Wordpress CLI + curl -fsSL "https://github.com/wp-cli/wp-cli/releases/download/v${WPCLI_VERSION}/wp-cli-${WPCLI_VERSION}.phar" -o /usr/local/bin/wp; \ + # Blackfire CLI + curl -fsSL "https://packages.blackfire.io/binaries/blackfire-agent/${BLACKFIRE_VERSION}/blackfire-cli-linux_${TARGETARCH}" -o /usr/local/bin/blackfire; \ + # Platform.sh CLI + curl -fsSL "https://github.com/platformsh/platformsh-cli/releases/download/v${PLATFORMSH_CLI_VERSION}/platform.phar" -o /usr/local/bin/platform; \ + # Acquia CLI + curl -fsSL "https://github.com/acquia/cli/releases/download/${ACQUIA_CLI_VERSION}/acli.phar" -o /usr/local/bin/acli; \ + # Pantheon Terminus + curl -fsSL "https://github.com/pantheon-systems/terminus/releases/download/${TERMINUS_VERSION}/terminus.phar" -o /usr/local/bin/terminus; \ + # jq (no arm64) + if [ "${TARGETARCH}" = "amd64" ]; then \ + curl -fsSL "https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64" -o /usr/local/bin/jq; \ + chmod +x /usr/local/bin/jq; \ + fi; \ + # yq + curl -fsSL "https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_${TARGETARCH}" -o /usr/local/bin/yq; \ + # Set Default Composer Version + ln -s /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer; \ + # Make all downloaded binaries executable in one shot + (cd /usr/local/bin && chmod +x composer1 composer2 drush8 drush drupal wp blackfire platform acli terminus yq); + +# Install Python3 from Debian repos +# This adds about 30MB to uncompressed image size. +# TODO: some other dependency in this image installs python2. Which one? +RUN set -xe; \ + apt-get update >/dev/null; \ + apt-get -y --no-install-recommends install >/dev/null \ + python3 \ + ;\ + # Cleanup + apt-get clean; rm -rf /var/lib/apt/lists/* + +# Install Ruby from Debian repos +RUN set -xe; \ + apt-get update >/dev/null; \ + apt-get -y --no-install-recommends install >/dev/null \ + ruby-full \ + ;\ + # Cleanup + apt-get clean; rm -rf /var/lib/apt/lists/* + +# All further RUN commands will run as the "docker" user +USER docker +SHELL ["/bin/bash", "-c"] + +# Don't use -x here, as the output may be excessive +RUN set -e; \ + \ + # Set drush8 as a global fallback for Drush Launcher + echo -e "\n""export DRUSH_LAUNCHER_FALLBACK=/usr/local/bin/drush8" >> $HOME/.profile; \ + # Composer based dependencies + # Add composer bin project level and global directories to PATH + # Project level comes first and thus takes precedence over the global one + echo -e "\n"'export PATH="$PATH:${PROJECT_ROOT:-/var/www}/vendor/bin"' >> $HOME/.profile; \ + echo -e "\n"'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> $HOME/.profile; \ + # Reload updated PATH from profile to make composer/drush/etc. visible below + . $HOME/.profile; \ + # Drupal Coder & WP Coding Standards w/ a matching version of PHP_CodeSniffer + composer global require drupal/coder wp-coding-standards/wpcs phpcompatibility/phpcompatibility-wp >/dev/null; \ + # Don't fix the indentation or installed_paths will not be set correctly + phpcs --config-set installed_paths \ +$HOME/.composer/vendor/drupal/coder/coder_sniffer/,\ +$HOME/.composer/vendor/wp-coding-standards/wpcs/,\ +$HOME/.composer/vendor/phpcompatibility/php-compatibility/PHPCompatibility/,\ +$HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp/PHPCompatibilityWP,\ +$HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie/PHPCompatibilityParagonieRandomCompat; \ + # Cleanup + composer clear-cache + +# Node.js (installed as user) +ENV \ + NVM_VERSION=0.38.0 \ + NODE_VERSION=14.17.3 \ + YARN_VERSION=1.22.10 +# Don't use -x here, as the output may be excessive +RUN set -e; \ + # NVM and a defaut Node.js version + export PROFILE="$HOME/.profile"; \ + curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh | bash >/dev/null; \ + # Reload profile to load nvm (needed by Yarn installation below) + . $HOME/.profile; \ + # Yarn + export YARN_PROFILE="$HOME/.profile"; \ + curl -fsSL https://yarnpkg.com/install.sh | bash -s -- --version ${YARN_VERSION} >/dev/null + +## Ruby (installed as user) via rvm +## Note: Disabled. rvm + its build dependecies bloat the image (~80MB) +## Debian 10 ships with Ruby 2.5, so we'll stick with that by default. +## It is still possible for the end user to switch to a different Ruby version via rvm. +#ENV \ +# RVM_VERSION_INSTALL=1.29.10 \ +# RUBY_VERSION_INSTALL=2.7.2 +## Don't use -x here, as the output may be excessive +#RUN set -e; \ +# # Export ruby gem bin path +# echo 'export PATH=$PATH:$(ruby -r rubygems -e "puts Gem.user_dir")/bin' >> $HOME/.profile; \ +# . $HOME/.profile; \ +# # Public GPG servers are not realiable, so downloading keys from rvm.io instead. +# #gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB +# # Import and trust rvm keys +# # mpapis@gmail.com +# curl -sSL https://rvm.io/mpapis.asc | gpg --batch --import -; \ +# echo 409B6B1796C275462A1703113804BB82D39DC0E3:6: | gpg --batch --import-ownertrust; \ +# # piotr.kuczynski@gmail.com +# curl -sSL https://rvm.io/pkuczynski.asc | gpg --batch --import -; \ +# echo 7D2BAF1CF37B13E2069D6956105BD0E739499BDB:6: | gpg --batch --import-ownertrust; \ +# \ +# echo 'rvm_autoupdate_flag=0' >> $HOME/.rvmrc; \ +# echo 'rvm_silence_path_mismatch_check_flag=1' >> $HOME/.rvmrc; \ +# curl -fsSL https://raw.githubusercontent.com/rvm/rvm/${RVM_VERSION_INSTALL}/binscripts/rvm-installer | bash -s -- --ignore-dotfiles --version ${RVM_VERSION_INSTALL}; \ +# { \ +# echo ''; \ +# echo 'export PATH="$PATH:$HOME/.rvm/bin"'; \ +# echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"'; \ +# } >> $HOME/.profile; \ +# # Reload $HOME/.profile to apply settings for the current shell +# . $HOME/.profile; \ +# \ +# # rvm.io does not currently have ruby binaries for Debian 9, so Ruby is compiled from source, which requires a bunch +# # of extra dependencies installed (rvm installs these automatically), which bloat this image: +# # rvm/ruby required packages: gawk, automake, bison, libffi-dev, libgdbm-dev, libncurses5-dev, libsqlite3-dev, libtool, libyaml-dev, sqlite3, zlib1g-dev, libgmp-dev, libreadline-dev, libssl-dev +# rvm install ruby-${RUBY_VERSION_INSTALL}; \ +# rvm use ruby-${RUBY_VERSION_INSTALL} --default; \ +# \ +# gem install --user-install bundler; \ +# # Have bundler install gems locally (./.bundle) by default +# echo -e "\n"'export BUNDLE_PATH=.bundle' >> $HOME/.profile; \ +# \ +# rvm cleanup all; \ +# rvm gemset globalcache enable + +# Python (installed as user) via pyenv +# Note: Disabled. pyenv + its build dependecies bloat the image (~300MB). +# Debian 10 ships with Python 3.7, so we'll stick with that by default. +# It is still possible for the end user to switch to a different python version via pyenv. +#ENV \ +# PYENV_VERSION_INSTALL=1.2.21 \ +# PYTHON_VERSION_INSTALL=3.8.3 +#RUN set -xe; \ +# # pyenv requires a bunch of build dependencies installed, which would bloat this image +# # See https://github.com/pyenv/pyenv/wiki/Common-build-problems#prerequisites +# sudo apt-get update >/dev/null; \ +# sudo apt-get -y --no-install-recommends install >/dev/null \ +# build-essential libssl-dev zlib1g-dev libbz2-dev \ +# libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \ +# xz-utils tk-dev libffi-dev liblzma-dev python-openssl git \ +# ;\ +# # Cleanup +# sudo apt-get clean; sudo rm -rf /var/lib/apt/lists/*; \ +# \ +# git clone --depth 1 -b v${PYENV_VERSION_INSTALL} https://github.com/pyenv/pyenv.git $HOME/.pyenv; \ +# rm -rf $HOME/.pyenv/.git; \ +# { \ +# echo ''; \ +# echo 'export PYENV_ROOT="$HOME/.pyenv"'; \ +# echo 'export PATH="$PYENV_ROOT/bin:$PATH"'; \ +# echo 'eval "$(pyenv init -)"'; \ +# } >> $HOME/.profile; \ +# # Reload $HOME/.profile to apply settings for the current shell +# . $HOME/.profile; \ +# pyenv install ${PYTHON_VERSION_INSTALL}; \ +# pyenv global ${PYTHON_VERSION_INSTALL} + +# Notify web container about started fin exec +RUN echo '(/opt/ping-web.sh &)' >> $HOME/.profile + +USER root +SHELL ["/bin/sh", "-c"] + +# Copy configs and scripts +COPY --chown=docker:docker config/.terminus /home/docker/.terminus +COPY --chown=docker:docker config/.ssh /home/docker/.ssh +COPY config/supervisor /etc/supervisor/conf.d +COPY startup.sh /opt/startup.sh +COPY healthcheck.sh /opt/healthcheck.sh +COPY ping-web.sh /opt/ping-web.sh +# PHP default settings, global overrides and fpm overrides +# PHP_VERSION is set upstream. The source code for the exact PHP version may not be available in Github +# TODO: For now, will just hardcode a specific version available on https://github.com/php/php-src/ +ADD https://raw.githubusercontent.com/php/php-src/PHP-8.0.5/php.ini-development /usr/local/etc/php/php.ini +COPY config/php/zz-php.ini /usr/local/etc/php/conf.d/zz-php.ini +COPY config/php/xdebug.ini /opt/docker-php-ext-xdebug.ini +COPY config/php/xhprof.ini /opt/docker-php-ext-xhprof.ini +COPY config/php/opcache.ini /opt/docker-php-ext-opcache.ini +COPY config/php/zz-php-fpm.conf /usr/local/etc/php-fpm.d/zz-php-fpm.conf + +ENV \ + # ssh-agent proxy socket (requires docksal/ssh-agent) + SSH_AUTH_SOCK=/.ssh-agent/proxy-socket \ + # Set TERM so text editors/etc. can be used + TERM=xterm \ + # Allow PROJECT_ROOT to be universally used in fin custom commands (inside and outside cli) + PROJECT_ROOT=/var/www \ + # Default values for HOST_UID and HOST_GUI to match the default Ubuntu user. These are used in startup.sh + HOST_UID=1000 \ + HOST_GID=1000 \ + # Delay in seconds between pings web from cli, while running fin exec. 0 - disabled + WEB_KEEPALIVE=0 \ + # xdebug disabled by default + XDEBUG_ENABLED=0 \ + XHPROF_ENABLED=0 \ + XHPROF_OUTPUT_DIR=/tmp/xhprof + +# TODO: [v3] remove and set these via docker-compose +EXPOSE 9000 +EXPOSE 22 +EXPOSE 3000 + +WORKDIR /var/www + +# Starter script +ENTRYPOINT ["/opt/startup.sh"] + +# By default, launch supervisord to keep the container running. +CMD ["supervisord"] + +# Health check script +HEALTHCHECK --interval=5s --timeout=1s --retries=12 CMD ["/opt/healthcheck.sh"] + + +# Visual Studio Code Server flavor +FROM cli as code-server + +# Run as docker, so we don't have to fix permissions +USER docker + +ARG HOME=/home/docker + +ENV \ + CODE_SERVER_VERSION=3.11.0 \ + VSCODE_XDEBUG_VERSION=1.16.1 \ + VSCODE_GITLENS_VERSION=11.6.0 \ + VSCODE_HOME="${HOME}/code-server" + +# Install code-server +RUN set -xe; \ + curl -fsSL "https://github.com/cdr/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server_${CODE_SERVER_VERSION}_${TARGETARCH}.deb" -o /tmp/code-server_${TARGETARCH}.deb; \ + sudo dpkg -i /tmp/code-server_${TARGETARCH}.deb; \ + rm -rf /tmp/*.* + +# Settings +COPY --chown=docker:docker config/code-server ${VSCODE_HOME} + +# Install extensions +# Note: Have to use --user-data-dir with --install-extension instead of --config +RUN set -xe; \ + code-server --user-data-dir=${VSCODE_HOME} --install-extension eamodio.gitlens@11.6.0; \ + code-server --user-data-dir=${VSCODE_HOME} --install-extension felixfbecker.php-debug@1.16.1 + +# Switch back to root (IMPORTANT!) +USER root diff --git a/8.0/Makefile b/8.0/Makefile new file mode 100644 index 00000000..b4fd4826 --- /dev/null +++ b/8.0/Makefile @@ -0,0 +1,79 @@ +-include ../tests/env_make +-include env_make + +IMAGE ?= docksal/cli +VERSION_PREFIX ?= php +VERSION ?= 8.0 +BUILD_IMAGE_TAG ?= $(IMAGE):$(VERSION_PREFIX)$(VERSION)-build +NAME = docksal-cli-$(VERSION)-$(GIT_SHA7) +CWD = $(shell pwd) + +# Improve write performance for /home/docker by turning it into a volume +VOLUMES = -v /home/docker + +.EXPORT_ALL_VARIABLES: + +.PHONY: build test push shell run start stop logs clean release + +build: + docker build -t $(BUILD_IMAGE_TAG) . + +# See https://docs.docker.com/buildx/working-with-buildx/ +# See https://github.com/docker/buildx +buildx: + docker buildx build --tag $(BUILD_IMAGE_TAG) . +buildx-with-cache: + docker buildx build --cache-from=type=registry,ref=ghcr.io/$(BUILD_IMAGE_TAG) --cache-to=type=inline --tag=$(BUILD_IMAGE_TAG) . + +test: + NAME=$(NAME) VERSION=$(VERSION) ../tests/test.bats + +push: + docker push $(BUILD_IMAGE_TAG) + +run: clean + docker run --rm --name $(NAME) -it $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) + +# Copy files into container instead of mounting from the host at runtime. +# This allows running tests on a remote docker instance. +start: clean + docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) + docker cp ../tests/. $(NAME):/var/www/ + docker start $(NAME) + +# Only copy docroot (not config overrides) +start-bare: clean + docker create --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(BUILD_IMAGE_TAG) + docker cp ../tests/docroot/. $(NAME):/var/www/docroot/ + docker start $(NAME) + +# Non-interactive and non-tty docker exec (uses LF instead of CRLF line endings) +exec: + @docker exec -u docker $(NAME) bash -lc "$(CMD)" + +# Interactive docker exec +exec-it: + @docker exec -u docker -it $(NAME) bash -ilc "$(CMD)" + +shell: + @docker exec -u docker -it $(NAME) bash -il + +stop: + docker stop $(NAME) + +logs: + docker logs $(NAME) + +logs-follow: + docker logs -f $(NAME) + +clean: + docker rm -vf $(NAME) >/dev/null 2>&1 || true + +tags: + @../.github/scripts/docker-tags.sh + +release: + @../scripts/docker-push.sh + +default: build diff --git a/8.0/config/.ssh/config b/8.0/config/.ssh/config new file mode 100644 index 00000000..74320faa --- /dev/null +++ b/8.0/config/.ssh/config @@ -0,0 +1,5 @@ +# Disable remote host key checking and warnings +Host * + StrictHostKeyChecking no + UserKnownHostsFile /dev/null + LogLevel ERROR diff --git a/8.0/config/.ssh/id_rsa.tmpl b/8.0/config/.ssh/id_rsa.tmpl new file mode 100644 index 00000000..8c6c22f1 --- /dev/null +++ b/8.0/config/.ssh/id_rsa.tmpl @@ -0,0 +1 @@ +{{ getenv "SECRET_SSH_PRIVATE_KEY" | base64.Decode }} \ No newline at end of file diff --git a/8.0/config/.terminus/config.yml b/8.0/config/.terminus/config.yml new file mode 100644 index 00000000..c7e89515 --- /dev/null +++ b/8.0/config/.terminus/config.yml @@ -0,0 +1,2 @@ +hide_update_message: true +hide_git_mode_warning: true \ No newline at end of file diff --git a/code-server/opt/code-server/settings.json b/8.0/config/code-server/User/settings.json similarity index 72% rename from code-server/opt/code-server/settings.json rename to 8.0/config/code-server/User/settings.json index 4dc66cab..1007d613 100644 --- a/code-server/opt/code-server/settings.json +++ b/8.0/config/code-server/User/settings.json @@ -22,5 +22,16 @@ "port": 9000 } ] - } + }, + // File associations + "files.associations": { + "*.inc": "php", + "*.module": "php", + "*.install": "php", + "*.theme": "php", + "*.tpl.php": "php", + "*.test": "php", + "*.php": "php" + }, + "workbench.colorTheme": "Default Dark+" } diff --git a/8.0/config/code-server/config.yaml.tmpl b/8.0/config/code-server/config.yaml.tmpl new file mode 100644 index 00000000..495d812e --- /dev/null +++ b/8.0/config/code-server/config.yaml.tmpl @@ -0,0 +1,9 @@ +user-data-dir: {{ getenv "VSCODE_HOME" }} +bind-addr: 0.0.0.0:8080 +cert: false +{{ if (getenv "IDE_PASSWORD") }} +auth: password +password: {{ getenv "IDE_PASSWORD" }} +{{ else }} +auth: none +{{ end }} diff --git a/8.0/config/php/opcache.ini b/8.0/config/php/opcache.ini new file mode 100644 index 00000000..bbc72325 --- /dev/null +++ b/8.0/config/php/opcache.ini @@ -0,0 +1,3 @@ +; Extention settings +[opcache] +opcache.preload=/var/www/.docksal/etc/php/preload.php diff --git a/8.0/config/php/xdebug.ini b/8.0/config/php/xdebug.ini new file mode 100644 index 00000000..90111271 --- /dev/null +++ b/8.0/config/php/xdebug.ini @@ -0,0 +1,12 @@ +[xdebug] +zend_extension=xdebug.so +; See https://xdebug.org/docs/all_settings#mode +xdebug.mode=debug +; xdebug.xdebug.client_host defaults to "localhost", which works with VS Code Server web IDE running locally +; For debugging from a "remote" host, xdebug.xdebug.client_host is set to ${DOCKSAL_HOST_IP} at runtime +; xdebug.xdebug.client_port defaults to "9003" in Xdebug 3. We use 9000 instead for backward compatibility with Xdebug 2. +xdebug.client_port=9000 +; TODO: Why do we have to set this? +xdebug.idekey=xdebug_session +; Increase max_nesting_level to support complex Drupal pages (default is 100) +xdebug.max_nesting_level=256 diff --git a/8.0/config/php/xhprof.ini b/8.0/config/php/xhprof.ini new file mode 100644 index 00000000..6c2e4dc9 --- /dev/null +++ b/8.0/config/php/xhprof.ini @@ -0,0 +1,2 @@ +[xhprof] +extension="xhprof.so" diff --git a/8.0/config/php/zz-php-fpm.conf b/8.0/config/php/zz-php-fpm.conf new file mode 100644 index 00000000..d4fb5e22 --- /dev/null +++ b/8.0/config/php/zz-php-fpm.conf @@ -0,0 +1,19 @@ +; PHP-FPM settings + +[global] +; This pid file is used for Docker healthcheck +pid = /run/php-fpm.pid + +[www] +user = docker +catch_workers_output = yes +listen = 0.0.0.0:9000 +clear_env = no + +; PHP (FPM) settings +; See zz-php.ini for global (CLI and FPM) PHP settings +php_value[memory_limit] = 256M +php_value[max_execution_time] = 300 +php_value[upload_max_filesize] = 500M +php_value[post_max_size] = 500M +php_value[max_input_vars] = 2000 diff --git a/8.0/config/php/zz-php.ini b/8.0/config/php/zz-php.ini new file mode 100644 index 00000000..c653442d --- /dev/null +++ b/8.0/config/php/zz-php.ini @@ -0,0 +1,18 @@ +; PHP global (CLI and FPM) settings +; To override settings for FPM use zz-php-fpm.conf +[php] +memory_limit = -1 +max_execution_time = 600 +date.timezone = UTC +display_errors = On +display_startup_errors = On + +[mail] +; Enable Mailhog integration by default +sendmail_path = '/usr/bin/msmtp -t --host=mail --port=1025' + +; Extention settings +[opcache] +opcache.memory_consumption = 128 +[blackfire] +blackfire.agent_socket = 'tcp://blackfire:8707' diff --git a/code-server/opt/code-server/supervisord-code-server.conf b/8.0/config/supervisor/supervisord-code-server.conf.tmpl similarity index 63% rename from code-server/opt/code-server/supervisord-code-server.conf rename to 8.0/config/supervisor/supervisord-code-server.conf.tmpl index 47342cff..7016f1a7 100644 --- a/code-server/opt/code-server/supervisord-code-server.conf +++ b/8.0/config/supervisor/supervisord-code-server.conf.tmpl @@ -1,6 +1,6 @@ # VS Code Server web IDE [program:code-server] # Using bash -lc here to load docker user profile (necessary for nvn/node to initialize) -command = gosu docker bash -lc '/usr/local/bin/code-server --user-data-dir=/home/docker/code-server -p 8080 /var/www --allow-http --no-auth' +command = gosu docker bash -lc '/usr/bin/code-server --config=${VSCODE_HOME}/config.yaml /var/www' stdout_logfile = /var/log/supervisor/code-server-stdout stderr_logfile = /var/log/supervisor/code-server-stderr diff --git a/8.0/config/supervisor/supervisord-crond.conf b/8.0/config/supervisor/supervisord-crond.conf new file mode 100644 index 00000000..33dbd8e1 --- /dev/null +++ b/8.0/config/supervisor/supervisord-crond.conf @@ -0,0 +1,5 @@ +[program:cron] +# Cron will only log to syslog and nothing else... +command = /usr/sbin/cron -f +stdout_logfile = /var/log/supervisor/cron-stdout +stderr_logfile = /var/log/supervisor/cron-stderr diff --git a/8.0/config/supervisor/supervisord-php-fpm.conf b/8.0/config/supervisor/supervisord-php-fpm.conf new file mode 100644 index 00000000..b4420872 --- /dev/null +++ b/8.0/config/supervisor/supervisord-php-fpm.conf @@ -0,0 +1,4 @@ +[program:php-fpm] +command = /usr/local/sbin/php-fpm +stdout_logfile = /var/log/supervisor/php-fpm-stdout +stderr_logfile = /var/log/supervisor/php-fpm-stderr diff --git a/8.0/config/supervisor/supervisord-sshd.conf b/8.0/config/supervisor/supervisord-sshd.conf new file mode 100644 index 00000000..de159108 --- /dev/null +++ b/8.0/config/supervisor/supervisord-sshd.conf @@ -0,0 +1,4 @@ +[program:sshd] +command = /usr/sbin/sshd -D +stdout_logfile = /var/log/supervisor/sshd-stdout +stderr_logfile = /var/log/supervisor/sshd-stderr diff --git a/8.0/config/supervisor/supervisord.conf b/8.0/config/supervisor/supervisord.conf new file mode 100644 index 00000000..32c7217a --- /dev/null +++ b/8.0/config/supervisor/supervisord.conf @@ -0,0 +1,6 @@ +[supervisord] +nodaemon = true +# debug prints output from all services to stdout/stderr. +# This way logs can be reviewed with docker logs. +# Additionalluy, logs from specific services are forwarded to individual files on disk. +loglevel = debug diff --git a/8.0/healthcheck.sh b/8.0/healthcheck.sh new file mode 100755 index 00000000..b4ab59d0 --- /dev/null +++ b/8.0/healthcheck.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# Initialization phase in startup.sh is complete +[[ -f /var/run/cli ]] || exit 1 + +# supervisor services are running +if [[ -f /run/supervisord.pid ]]; then + if [[ "${IDE_ENABLED}" == "1" ]]; then + # IDE mode + ps aux | grep code-server >/dev/null || exit 1 + else + # php-fpm/cli mode + [[ -f /run/php-fpm.pid ]] || exit 1 + [[ -f /run/sshd.pid ]] || exit 1 + fi +fi diff --git a/8.0/ping-web.sh b/8.0/ping-web.sh new file mode 100755 index 00000000..6a5ba7b8 --- /dev/null +++ b/8.0/ping-web.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Notify web container about started fin exec +if [[ "${WEB_KEEPALIVE}" != "0" ]] && [[ "${VIRTUAL_HOST}" != "" ]] +then + while true + do + curl -s -m 1 ${VIRTUAL_HOST}/exec_in_progress_inside_cli >/dev/null 2>&1 + sleep ${WEB_KEEPALIVE} + done +fi diff --git a/8.0/startup.sh b/8.0/startup.sh new file mode 100755 index 00000000..11e2d082 --- /dev/null +++ b/8.0/startup.sh @@ -0,0 +1,238 @@ +#!/bin/bash + +# This script is running as root by default. +# Switching to the docker user can be done via "gosu docker ". + +HOME_DIR='/home/docker' + +DEBUG=${DEBUG:-0} +# Turn debugging ON when cli is started in the service mode +[[ "$1" == "supervisord" ]] && DEBUG=1 +echo-debug () +{ + [[ "$DEBUG" != 0 ]] && echo "$(date +"%F %H:%M:%S") | $@" +} + +uid_gid_reset () +{ + if [[ "$HOST_UID" != "$(id -u docker)" ]] || [[ "$HOST_GID" != "$(id -g docker)" ]]; then + echo-debug "Updating docker user uid/gid to $HOST_UID/$HOST_GID to match the host user uid/gid..." + usermod -u "$HOST_UID" -o docker + groupmod -g "$HOST_GID" -o "$(id -gn docker)" + fi +} + +xdebug_enable () +{ + echo-debug "Enabling xdebug..." + ln -s /opt/docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/ +} + +xhprof_enable () +{ + echo-debug "Enabling xhprof..." + cp /opt/docker-php-ext-xhprof.ini /usr/local/etc/php/conf.d/ + # Output directory to the ini file + echo "xhprof.output_dir = ${XHPROF_OUTPUT_DIR}" >> /usr/local/etc/php/conf.d/docker-php-ext-xhprof.ini + # Try to create directory if it doesn't exist + mkdir ${XHPROF_OUTPUT_DIR} || true + # Change owner of directory + chown docker:docker ${XHPROF_OUTPUT_DIR} +} + +opcache_preload_enable() +{ + echo-debug "Enabling opcache preload..." + ln -s /opt/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/ +} + +ide_mode_enable () +{ + echo-debug "Enabling web IDE..." + # Enabled only code-server service (disabled all other services) + # TODO: split IDE/cli and php-fpm entirely + rm -f /etc/supervisor/conf.d/supervisord-*.conf + render_tmpl "/etc/supervisor/conf.d/supervisord-code-server.conf" + render_tmpl "${VSCODE_HOME}/config.yaml" +} + +# Creates symlinks to project level overrides if they exist +php_settings () +{ + php_ini=/var/www/.docksal/etc/php/php.ini + if [[ -f ${php_ini} ]]; then + echo-debug "Found project level overrides for PHP. Including:" + echo-debug "${php_ini}" + ln -s /var/www/.docksal/etc/php/php.ini /usr/local/etc/php/conf.d/zzz-php.ini + fi + + php_fpm_conf=/var/www/.docksal/etc/php/php-fpm.conf + if [[ -f ${php_fpm_conf} ]]; then + echo-debug "Found project level overrides for PHP-FPM. Including:" + echo-debug "${php_fpm_conf}" + ln -s ${php_fpm_conf} /usr/local/etc/php-fpm.d/zzz-php-fpm.conf + fi +} + +add_ssh_key () +{ + echo-debug "Adding a private SSH key from SECRET_SSH_PRIVATE_KEY..." + render_tmpl "$HOME_DIR/.ssh/id_rsa" + chmod 0600 "$HOME_DIR/.ssh/id_rsa" +} + +# Helper function to render configs from go templates using gomplate +render_tmpl () +{ + local file="${1}" + local tmpl="${1}.tmpl" + + if [[ -f "${tmpl}" ]]; then + echo-debug "Rendering template: ${tmpl}..." + # gomplate started throwing an empty line into stderr in v3.7.0, so we have to mute it below + gomplate --file "${tmpl}" --out "${file}" &>/dev/null + else + echo-debug "Error: Template file not found: ${tmpl}" + return 1 + fi +} + +# Helper function to loop through all environment variables prefixed with SECRET_ and +# convert to the equivalent variable without SECRET. +# Example: SECRET_TERMINUS_TOKEN => TERMINUS_TOKEN. +convert_secrets () +{ + eval 'secrets=(${!SECRET_@})' + for secret_key in "${secrets[@]}"; do + key=${secret_key#SECRET_} + secret_value=${!secret_key} + + # Write new variables to /etc/profile.d/secrets.sh to make them available for all users/sessions + echo "export ${key}=\"${secret_value}\"" | tee -a "/etc/profile.d/secrets.sh" >/dev/null + + # Also export new variables here + # This makes them available in the server/php-fpm environment + eval "export ${key}=${secret_value}" + done +} + +# Pantheon (terminus) login +terminus_login () +{ + echo-debug "Authenticating with Pantheon..." + # This has to be done using the docker user via su to load the user environment + # Note: Using 'su -l' to initiate a login session and have .profile sourced for the docker user + local command="terminus auth:login --machine-token='${TERMINUS_TOKEN}'" + local output=$(su -l docker -c "${command}" 2>&1) + if [[ $? != 0 ]]; then + echo-debug "ERROR: Pantheon authentication failed." + echo + echo "$output" + echo + fi +} + +# Acquia CLI login +acli_login () +{ + echo-debug "Authenticating with Acquia..." + # This has to be done using the docker user via su to load the user environment + # Note: Using 'su -l' to initiate a login session and have .profile sourced for the docker user + local command="acli auth:login --key='${ACQUIA_CLI_KEY}' --secret='${ACQUIA_CLI_SECRET}' --no-interaction" + local output=$(su -l docker -c "${command}" 2>&1) + if [[ $? != 0 ]]; then + echo-debug "ERROR: Acquia authentication failed." + echo + echo "$output" + echo + fi +} + +# Git settings +git_settings () +{ + # These must be run as the docker user + echo-debug "Configuring git..." + # Set default git settings if none have been passed + # See https://github.com/docksal/service-cli/issues/124 + gosu docker git config --global user.email "${GIT_USER_EMAIL:-cli@docksal.io}" + gosu docker git config --global user.name "${GIT_USER_NAME:-Docksal CLI}" +} + +# Inject a private SSH key if provided +[[ "$SECRET_SSH_PRIVATE_KEY" != "" ]] && add_ssh_key + +# Set Composer Version +[[ "${COMPOSER_DEFAULT_VERSION}" != "" ]] && [[ -f /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} ]] && ln -sf /usr/local/bin/composer${COMPOSER_DEFAULT_VERSION} /usr/local/bin/composer + +# Convert all Environment Variables Prefixed with SECRET_ +convert_secrets + +# Docker user uid/gid mapping to the host user uid/gid +[[ "$HOST_UID" != "" ]] && [[ "$HOST_GID" != "" ]] && uid_gid_reset + +# Enable xdebug +[[ "$XDEBUG_ENABLED" != "" ]] && [[ "$XDEBUG_ENABLED" != "0" ]] && xdebug_enable + +# Enable xdebug +[[ "$XHPROF_ENABLED" != "" ]] && [[ "$XHPROF_ENABLED" != "0" ]] && xhprof_enable + +# Enable opcache preload +[[ -f "/var/www/.docksal/etc/php/preload.php" ]] && opcache_preload_enable + +# Enable web IDE +[[ "$IDE_ENABLED" != "" ]] && [[ "$IDE_ENABLED" != "0" ]] && ide_mode_enable + +# Include project level PHP settings if found +php_settings + +# Make sure permissions are correct (after uid/gid change and COPY operations in Dockerfile) +# To not bloat the image size, permissions on the home folder are reset at runtime. +echo-debug "Resetting permissions on $HOME_DIR and /var/www..." +chown "${HOST_UID:-1000}:${HOST_GID:-1000}" -R "$HOME_DIR" +# Docker resets the project root folder permissions to 0:0 when cli is recreated (e.g. an env variable updated). +# We apply a fix/workaround for this at startup (non-recursive). +chown "${HOST_UID:-1000}:${HOST_GID:-1000}" /var/www + +# These have to happen after the home directory permissions are reset, +# otherwise the docker user may not have write access to /home/docker, where the auth session data is stored. +# Automatically authenticate with Pantheon if Terminus token is present +[[ "$TERMINUS_TOKEN" != "" ]] && terminus_login + +# Authenticate to Acquia CLI +[[ "$ACQUIA_CLI_KEY" != "" ]] && [[ "$ACQUIA_CLI_SECRET" != "" ]] && acli_login + +# If crontab file is found within project add contents to user crontab file. +if [[ -f ${PROJECT_ROOT}/.docksal/services/cli/crontab ]]; then + echo-debug "Loading crontab..." + cat ${PROJECT_ROOT}/.docksal/services/cli/crontab | crontab -u docker - +fi + +# Apply git settings +[[ "$GIT_USER_EMAIL" != "" ]] && [[ "$GIT_USER_NAME" != "" ]] && git_settings + +# Initialization steps completed. Create a pid file to mark the container as healthy +echo-debug "Preliminary initialization completed." +touch /var/run/cli + +# Execute a custom startup script if present +if [[ -x ${PROJECT_ROOT}/.docksal/services/cli/startup.sh ]]; then + echo-debug "Running custom startup script..." + # TODO: should we source the script instead? + su -l docker -c "${PROJECT_ROOT}/.docksal/services/cli/startup.sh" + if [[ $? == 0 ]]; then + echo-debug "Custom startup script executed successfully." + else + echo-debug "ERROR: Custom startup script execution failed." + fi +fi + +# Execute passed CMD arguments +echo-debug "Passing execution to: $*" +# Service mode (run as root) +if [[ "$1" == "supervisord" ]]; then + exec gosu root supervisord -c /etc/supervisor/supervisord.conf +# Command mode (run as docker user) +else + exec gosu docker "$@" +fi diff --git a/8.0/tests/essential-binaries.sh b/8.0/tests/essential-binaries.sh new file mode 100755 index 00000000..cdea93df --- /dev/null +++ b/8.0/tests/essential-binaries.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +binaries_amd64=\ +'cat +convert +curl +dig +g++ +ghostscript +git +git-lfs +gcc +jq +html2text +less +make +mc +more +mysql +nano +nslookup +ping +psql +pv +rsync +sudo +unzip +wget +yq +zip' + +binaries_arm64=\ +'cat +convert +curl +dig +g++ +ghostscript +git +git-lfs +gcc +html2text +less +make +mc +more +mysql +nano +nslookup +ping +psql +pv +rsync +sudo +unzip +wget +yq +zip' + +# Use the docker reported architecture and not the hosts (uname -m). +# docker arch may not be the same as hosts's arch (e.g., when using a remote docker instance). +case "$(docker info -f '{{ .Architecture }}')" in + x86_64) echo "${binaries_amd64}" ;; + amd64) echo "${binaries_amd64}" ;; + aarch64) echo "${binaries_arm64}" ;; + arm64) echo "${binaries_arm64}" ;; + * ) false;; +esac diff --git a/8.0/tests/php-modules.sh b/8.0/tests/php-modules.sh new file mode 100755 index 00000000..8037c6d1 --- /dev/null +++ b/8.0/tests/php-modules.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash + +php_modules_amd64=\ +'[PHP Modules] +apcu +bcmath +blackfire +bz2 +calendar +Core +ctype +curl +date +dom +exif +fileinfo +filter +ftp +gd +gettext +gnupg +hash +iconv +imagick +imap +intl +json +ldap +libxml +mbstring +memcached +mysqli +mysqlnd +openssl +pcntl +pcre +PDO +pdo_mysql +pdo_pgsql +pdo_sqlite +pdo_sqlsrv +pgsql +Phar +posix +readline +redis +Reflection +session +SimpleXML +soap +sockets +sodium +SPL +sqlite3 +sqlsrv +ssh2 +standard +sysvsem +tokenizer +xml +xmlreader +xmlwriter +xsl +Zend OPcache +zip +zlib + +[Zend Modules] +Zend OPcache +blackfire +' + +php_modules_arm64=\ +'[PHP Modules] +apcu +bcmath +blackfire +bz2 +calendar +Core +ctype +curl +date +dom +exif +fileinfo +filter +ftp +gd +gettext +gnupg +hash +iconv +imagick +imap +intl +json +ldap +libxml +mbstring +memcached +mysqli +mysqlnd +openssl +pcntl +pcre +PDO +pdo_mysql +pdo_pgsql +pdo_sqlite +pgsql +Phar +posix +readline +redis +Reflection +session +SimpleXML +soap +sockets +sodium +SPL +sqlite3 +ssh2 +standard +sysvsem +tokenizer +xml +xmlreader +xmlwriter +xsl +Zend OPcache +zip +zlib + +[Zend Modules] +Zend OPcache +blackfire +' + +# Use the docker reported architecture and not the hosts (uname -m). +# docker arch may not be the same as hosts's arch (e.g., when using a remote docker instance). +case "$(docker info -f '{{ .Architecture }}')" in + x86_64) echo "${php_modules_amd64}" ;; + amd64) echo "${php_modules_amd64}" ;; + aarch64) echo "${php_modules_arm64}" ;; + arm64) echo "${php_modules_arm64}" ;; + * ) false;; +esac diff --git a/Makefile b/Makefile index 8a883cdd..27a3b27f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Makefile # -DIRS = 7.3 7.4 +DIRS = 7.3 7.4 8.0 # the sets of directories to do various things in BUILDDIRS = $(DIRS:%=build-%) INSTALLDIRS = $(DIRS:%=install-%) diff --git a/README.md b/README.md index 865a97a2..c6cfa38c 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,13 @@ This image(s) is part of the [Docksal](https://docksal.io) image library. ## Versions and image tag naming convention - Stable versions - - `2.11-php7.3`, `php7.3`, `latest` - PHP 7.3 - - `2.11-php7.4`, `php7.4` - PHP 7.4 + - `php7.3-2.14`, `php7.3-2`, `php7.3` - PHP 7.3 + - `php7.4-2.14`, `php7.4-2`, `php7.4`, `latest` - PHP 7.4 + - `php8.0-2.14`, `php8.0`, `php8.0` - PHP 8.0 - Development versions - - `edge-php7.3` - PHP 7.3 - - `edge-php7.4` - PHP 7.4 + - `php7.3-edge` - PHP 7.3 + - `php7.4-edge` - PHP 7.4 + - `php8.0-edge` - PHP 8.0 ## PHP @@ -33,7 +35,6 @@ This image(s) is part of the [Docksal](https://docksal.io) image library. - composer v1 & v2 - drush (Drupal) - drush launcher with a fallback to a global drush 8 - - registry_rebuild module - coder-8.x + phpcs - drupal console launcher (Drupal) - wp-cli (Wordpress) @@ -72,12 +73,12 @@ cli ## NodeJS - nvm -- node v12.18.1 (following NodeJS LTS release cycle) +- node v14.17.3 (following NodeJS LTS release cycle) - yarn NodeJS is installed via `nvm` in the `docker` user's profile inside the image (`/home/docker/.nvm`). -If you need a different version of node, use `nvm` to install it, e.g, `nvm install 11.6.0`. +If you need a different version of node, use `nvm` to install it, e.g., `nvm install 11.6.0`. Then, use `nvm use 11.6.0` to use it in the current session or `nvm alias default 11.6.0` to use it by default. ## Python @@ -87,7 +88,7 @@ Then, use `nvm use 11.6.0` to use it in the current session or `nvm alias defaul This image comes with a system level installed Python version from upstream (Debian 9). -Additional versions can be installed via `pyenv`, e.g. `pyenv install 3.7.0`. +Additional versions can be installed via `pyenv`, e.g., `pyenv install 3.7.0`. Then, use `pyenv local 3.7.0` to use it in the current session or `pyenv global 3.7.0` to set is as the default. Note: additional versions will be installed in the `docker` user's profile inside the image (`/home/docker/.pyenv`). @@ -101,7 +102,7 @@ Note: additional versions will be installed in the `docker` user's profile insid Ruby is installed via `rvm` in the `docker` user's profile inside the image (`/home/docker/.rvm`). -If you need a different version, use `rvm` to install it, e.g, `rvm install 2.5.1`. +If you need a different version, use `rvm` to install it, e.g., `rvm install 2.5.1`. Then, `rvm use 2.5.1` to use it in the current session or `rvm --default use 2.5.1` to use it by default. ## Notable console tools @@ -117,9 +118,9 @@ Then, `rvm use 2.5.1` to use it in the current session or `rvm --default use 2.5 ## Hosting provider tools -- `acquiacli` for Acquia Cloud APIv2 ([Acquia](https://www.acquia.com/)) -- `terminus` ([Pantheon](https://pantheon.io/)) -- `platform` ([Platform.sh](https://platform.sh/)) +- `acli` for Acquia Cloud APIv2 ([Acquia](https://docs.acquia.com/acquia-cli/)) +- `terminus` ([Pantheon](https://pantheon.io/features/terminus-command-line-interface)) +- `platform` ([Platform.sh](https://docs.platform.sh/development/cli.html)) Also, see the [Secrets](#secrets) section below for more information on managing and using your hosting provider keys. @@ -154,9 +155,9 @@ by the SSH client **in addition** to the keys loaded in `docksal-ssh-agent` when from within `cli`. This is useful when you need a project stack to inherit a private SSH key that is not shared with other project stacks -on the same host (e.g. in shared CI environments). +on the same host (e.g., in shared CI environments). -The value must be base64 encoded, i.e: +The value must be base64 encoded, i.e.: ```bash cat /path/to/some_key_rsa | base64 diff --git a/code-server/Dockerfile b/code-server/Dockerfile deleted file mode 100644 index 77eb4c5e..00000000 --- a/code-server/Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -ARG FROM_TAG - -FROM docksal/cli:${FROM_TAG} - -# Run as docker, so we don't have to fix permissions -USER docker - -# Run as docker, so we don't have to fix permissions -USER docker - -ARG HOME=/home/docker - -ENV \ - # TODO: 2.x versions do not yet work with xdebug - CODE_SERVER_VERSION=1.1156-vsc1.33.1 \ - VSCODE_HOME="${HOME}/code-server" \ - VSCODE_EXT_DIRECTORY="${HOME}/code-server/extensions" \ - VSCODE_XDEBUG_VERSION=1.13.0 \ - VSCODE_GITLENS_VERSION=9.9.3 - -# Install code-server -RUN \ - set -xe; \ - curl -fsSL "https://github.com/cdr/code-server/releases/download/${CODE_SERVER_VERSION}/code-server${CODE_SERVER_VERSION}-linux-x64.tar.gz" -o /tmp/code-server.tar.gz; \ - tar -zxv --file=/tmp/code-server.tar.gz --directory=/tmp --strip-components=1; \ - sudo mv /tmp/code-server /usr/local/bin/; rm -rf /tmp/*.* - -# Settings and scripts -COPY opt/code-server /opt/code-server - -# Install extensions -RUN \ - set -xe; \ - mkdir -p ${VSCODE_EXT_DIRECTORY}; \ - /opt/code-server/install-vscode-extension https://github.com/felixfbecker/vscode-php-debug/releases/download/v${VSCODE_XDEBUG_VERSION}/php-debug.vsix felixfbecker.php-debug-${VSCODE_XDEBUG_VERSION}; \ - /opt/code-server/install-vscode-extension https://github.com/eamodio/vscode-gitlens/releases/download/v${VSCODE_GITLENS_VERSION}/gitlens-${VSCODE_GITLENS_VERSION}.vsix eamodio.gitlens-${VSCODE_GITLENS_VERSION} - -# Switch back to root (IMPORTANT!) -USER root diff --git a/code-server/Makefile b/code-server/Makefile deleted file mode 100644 index b0b26540..00000000 --- a/code-server/Makefile +++ /dev/null @@ -1,57 +0,0 @@ --include ../tests/env_make --include env_make - -VERSION ?= 7.3 -REPO = docksal/cli -FROM_TAG = build-$(VERSION) -TAG = $(FROM_TAG)-ide -NAME = docksal-cli-$(VERSION)-ide -CWD = $(shell pwd) - -# Improve write performance for /home/docker by turning it into a volume -VOLUMES += -v /home/docker - -.PHONY: build test push shell run start stop logs clean release - -build: - docker build --build-arg FROM_TAG=$(FROM_TAG) -t $(REPO):$(TAG) . - -test: - IMAGE=$(REPO):$(TAG) NAME=$(NAME) tests/test.bats - -push: - docker push $(REPO):$(TAG) - -run: clean - docker run --rm --name $(NAME) -it $(PORTS) $(VOLUMES) $(ENV) $(REPO):$(TAG) - -start: clean - docker run -d --name $(NAME) $(PORTS) $(VOLUMES) $(ENV) $(REPO):$(TAG) - -# Non-interactive and non-tty docker exec (uses LF instead of CRLF line endings) -exec: - @docker exec -u docker $(NAME) bash -lc "$(CMD)" - -# Interactive docker exec -exec-it: - @docker exec -u docker -it $(NAME) bash -ilc "$(CMD)" - -shell: - @docker exec -u docker -it $(NAME) bash -il - -stop: - docker stop $(NAME) - -logs: - docker logs $(NAME) - -logs-follow: - docker logs -f $(NAME) - -clean: - docker rm -vf $(NAME) >/dev/null 2>&1 || true - -release: build - make push -e TAG=$(TAG) - -default: build diff --git a/code-server/opt/code-server/install-vscode-extension b/code-server/opt/code-server/install-vscode-extension deleted file mode 100755 index e50b208e..00000000 --- a/code-server/opt/code-server/install-vscode-extension +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -PLUGIN_URL=$1 -PLUGIN_DIRECTORY=$2 - -curl -fsSL "${PLUGIN_URL}" -o /tmp/extension.zip -unzip -qq /tmp/extension.zip -d /tmp/extension -mv /tmp/extension/extension ${VSCODE_EXT_DIRECTORY}/${PLUGIN_DIRECTORY} -rm -rf /tmp/extension.zip /tmp/extension diff --git a/code-server/tests/test.bats b/code-server/tests/test.bats deleted file mode 100755 index 8c0aebca..00000000 --- a/code-server/tests/test.bats +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env bats - -# Debugging -teardown() { - echo - # TODO: figure out how to deal with this (output from previous run commands showing up along with the error message) - echo "Note: ignore the lines between \"...failed\" above and here" - echo - echo "Status: ${status}" - echo "Output:" - echo "================================================================" - echo "${output}" - echo "================================================================" -} - -# Checks container health status (if available) -# Relies on healchecks introduced in docksal/cli v1.3.0+, uses `sleep` as a fallback -# @param $1 container id/name -_healthcheck () -{ - local health_status - health_status=$(docker inspect --format='{{json .State.Health.Status}}' "$1" 2>/dev/null) - - # Wait for 5s then exit with 0 if a container does not have a health status property - # Necessary for backward compatibility with images that do not support health checks - if [[ $? != 0 ]]; then - echo "Waiting 10s for container to start..." - sleep 10 - return 0 - fi - - # If it does, check the status - echo ${health_status} | grep '"healthy"' >/dev/null 2>&1 -} - -# Waits for containers to become healthy -_healthcheck_wait () -{ - # Wait for cli to become ready by watching its health status - local container_name="${NAME}" - local delay=5 - local timeout=30 - local elapsed=0 - - until _healthcheck "$container_name"; do - echo "Waiting for $container_name to become ready..." - sleep ${delay}; - - # Give the container 30s to become ready - elapsed=$((elapsed + delay)) - if ((elapsed > timeout)); then - echo "$container_name heathcheck failed" - exit 1 - fi - done - - return 0 -} - -# To work on a specific test: -# run `export SKIP=1` locally, then comment skip in the test you want to debug - -@test "VS Code Server" { - [[ $SKIP == 1 ]] && skip - - ### Setup ### - make start - - run _healthcheck_wait - unset output - # This is a dirty hack to get tests to pass on Travis. - # TODO: This should be replaced with a proper code-server healthcheck in Dockerfile - sleep 10 - - ### Tests ### - - run make logs - echo "$output" | grep "Documentation on securing your setup" - unset output - - ### Cleanup ### - make clean -} diff --git a/scripts/docker-push.sh b/scripts/docker-push.sh deleted file mode 100755 index a681498b..00000000 --- a/scripts/docker-push.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env bash - -# ----- Helper functions ----- # - -is_edge () -{ - [[ "${TRAVIS_BRANCH}" == "develop" ]] -} - -is_stable () -{ - [[ "${TRAVIS_BRANCH}" == "master" ]] -} - -is_release () -{ - [[ "${TRAVIS_TAG}" != "" ]] -} - -# Check whether the current build is for a pull request -is_pr () -{ - [[ "${TRAVIS_PULL_REQUEST}" != "false" ]] -} - -is_latest () -{ - [[ "${VERSION}" == "${LATEST_VERSION}" ]] -} - -# Tag and push an image -# $1 - source image -# $2 - target image -tag_and_push () -{ - local source=$1 - local target=$2 - - # Base image - echo "Pushing ${target} image ..." - docker tag ${source} ${target} - docker push ${target} -} - -# ---------------------------- # - -# Extract version parts from release tag -IFS='.' read -a ver_arr <<< "$TRAVIS_TAG" -VERSION_MAJOR=${ver_arr[0]#v*} # 2.7.0 => "2" -VERSION_MINOR=${ver_arr[1]} # "2.7.0" => "7" - -# Set tags if exists -SOFTWARE_VERSION="${SOFTWARE_VERSION:+-${SOFTWARE_VERSION}}" - -# Possible docker image tags -# "image:tag" pattern: :[-][-] -IMAGE_TAG_EDGE="edge${SOFTWARE_VERSION}" # e.g., edge[-SOFTWARE_VERSION] -IMAGE_TAG_STABLE="stable${SOFTWARE_VERSION}" # e.g., stable[-SOFTWARE_VERSION] -IMAGE_TAG_RELEASE_MAJOR="${VERSION_MAJOR}${SOFTWARE_VERSION}" # e.g., 2[-SOFTWARE_VERSION] -IMAGE_TAG_RELEASE_MAJOR_MINOR="${VERSION_MAJOR}.${VERSION_MINOR}${SOFTWARE_VERSION}" # e.g., 2.7[-SOFTWARE_VERSION] -IMAGE_TAG_LATEST="latest" - -# Skip pull request builds -is_pr && exit - -docker login -u "${DOCKER_USER}" -p "${DOCKER_PASS}" - -# Push images -if is_edge; then - tag_and_push ${REPO}:${BUILD_TAG} ${REPO}:${IMAGE_TAG_EDGE} -elif is_stable; then - tag_and_push ${REPO}:${BUILD_TAG} ${REPO}:${IMAGE_TAG_STABLE} -elif is_release; then - # Have stable, major, minor tags match - tag_and_push ${REPO}:${BUILD_TAG} ${REPO}:${IMAGE_TAG_STABLE} - tag_and_push ${REPO}:${BUILD_TAG} ${REPO}:${IMAGE_TAG_RELEASE_MAJOR} - tag_and_push ${REPO}:${BUILD_TAG} ${REPO}:${IMAGE_TAG_RELEASE_MAJOR_MINOR} -else - # Exit if not on develop, master or release tag - exit -fi - -# Special case for the "latest" tag -# Push (base image only) on stable and release builds -if is_latest && (is_stable || is_release); then - tag_and_push ${REPO}:${BUILD_TAG} ${REPO}:${IMAGE_TAG_LATEST} -fi diff --git a/tests/scripts/php-fpm.sh b/tests/docroot/php-fpm.sh similarity index 100% rename from tests/scripts/php-fpm.sh rename to tests/docroot/php-fpm.sh diff --git a/tests/env_make b/tests/env_make index 5b19ab1e..57a31e52 100644 --- a/tests/env_make +++ b/tests/env_make @@ -1,7 +1,3 @@ -VOLUMES = \ - -v /home/docker \ - -v $(CWD)/../tests:/var/www - ENV = \ -e XDEBUG_ENABLED \ -e SECRET_BLACKFIRE_CLIENT_ID \ diff --git a/tests/test.bats b/tests/test.bats index 753cdf03..a2f1f206 100755 --- a/tests/test.bats +++ b/tests/test.bats @@ -64,7 +64,7 @@ _healthcheck_wait () [[ $SKIP == 1 ]] && skip ### Setup ### - make start + make start-bare run _healthcheck_wait unset output @@ -72,35 +72,7 @@ _healthcheck_wait () ### Tests ### # List of binaries to check - binaries='\ - cat \ - convert \ - curl \ - dig \ - g++ \ - ghostscript \ - git \ - git-lfs \ - gcc \ - html2text \ - jq \ - less \ - make \ - mc \ - more \ - mysql \ - nano \ - nslookup \ - ping \ - psql \ - pv \ - rsync \ - sudo \ - unzip \ - wget \ - yq \ - zip \ - ' + binaries=$(./tests/essential-binaries.sh) # Check all binaries in a single shot run make exec -e CMD="type $(echo ${binaries} | xargs)" @@ -115,12 +87,7 @@ _healthcheck_wait () [[ $SKIP == 1 ]] && skip ### Setup ### - docker rm -vf "$NAME" >/dev/null 2>&1 || true - docker run --name "$NAME" -d \ - -v /home/docker \ - -v $(pwd)/../tests/docroot:/var/www/docroot \ - "$IMAGE" - docker cp $(pwd)/../tests/scripts "$NAME:/var/www/" + make start-bare run _healthcheck_wait unset output @@ -131,7 +98,7 @@ _healthcheck_wait () # "sed -E 's/[[:space:]]{2,}/ => /g'" - makes the HTML phpinfo output easier to parse. It will transforms # "memory_limit 256M 256M" # into "memory_limit => 256M => 256M", which is much easier to parse - phpInfo=$(docker exec -u docker "$NAME" bash -c "/var/www/scripts/php-fpm.sh phpinfo.php | sed -E 's/[[:space:]]{2,}/ => /g'") + phpInfo=$(docker exec -u docker "$NAME" bash -c "/var/www/docroot/php-fpm.sh phpinfo.php | sed -E 's/[[:space:]]{2,}/ => /g'") output=$(echo "$phpInfo" | grep "memory_limit") echo "$output" | grep "256M => 256M" @@ -141,7 +108,7 @@ _healthcheck_wait () echo "$output" | grep '/usr/bin/msmtp -t --host=mail --port=1025 => /usr/bin/msmtp -t --host=mail --port=1025' unset output - run docker exec -u docker "$NAME" /var/www/scripts/php-fpm.sh nonsense.php + run docker exec -u docker "$NAME" /var/www/docroot/php-fpm.sh nonsense.php echo "$output" | grep "Status: 404 Not Found" unset output @@ -168,12 +135,12 @@ _healthcheck_wait () unset output # Check PHP modules - run bash -lc "docker exec -u docker '${NAME}' php -m | diff php-modules.txt -" + run bash -lc "docker exec -u docker '${NAME}' php -m | diff <(./tests/php-modules.sh) -" [[ ${status} == 0 ]] unset output ### Cleanup ### - docker rm -vf "$NAME" >/dev/null 2>&1 || true + make clean } # Examples of using Makefile commands @@ -190,7 +157,7 @@ _healthcheck_wait () ### Tests ### # Check PHP FPM settings overrides - run make exec -e CMD='/var/www/scripts/php-fpm.sh phpinfo.php' + run make exec -e CMD='/var/www/docroot/php-fpm.sh phpinfo.php' echo "$output" | grep "memory_limit" | grep "512M" unset output @@ -259,18 +226,14 @@ _healthcheck_wait () [[ ${status} == 0 ]] unset output - # Check Magento 2 Code Generator version - # TODO: this needs to be replaced with the actual version check - # See https://github.com/staempfli/magento2-code-generator/issues/15 - #run docker exec -u docker "$NAME" bash -lc 'mg2-codegen --version | grep "^mg2-codegen ${MG_CODEGEN_VERSION}$"' - run docker exec -u docker "$NAME" bash -lc 'set -x; mg2-codegen --version | grep "^mg2-codegen @git-version@$"' - [[ ${status} == 0 ]] - unset output - # Check Terminus version - run docker exec -u docker "$NAME" bash -lc 'set -x; terminus --version | grep "^Terminus ${TERMINUS_VERSION}$"' - [[ ${status} == 0 ]] - unset output + # Terminus does not yet support PHP 8.0 + # See https://github.com/pantheon-systems/terminus/issues/2113 + if [[ "${VERSION}" != "8.0" ]]; then + run docker exec -u docker "$NAME" bash -lc 'set -x; terminus --version | grep "^Terminus ${TERMINUS_VERSION}$"' + [[ ${status} == 0 ]] + unset output + fi # Check Platform CLI version run docker exec -u docker "$NAME" bash -lc 'set -x; platform --version | grep "Platform.sh CLI ${PLATFORMSH_CLI_VERSION}"' @@ -333,7 +296,9 @@ _healthcheck_wait () unset output # ruby - run docker exec -u docker "$NAME" bash -lc 'ruby --version | grep "${RUBY_VERSION_INSTALL}"' + #run docker exec -u docker "$NAME" bash -lc 'ruby --version | grep "${RUBY_VERSION_INSTALL}"' + # Default Ruby version in Debian 10 = 2.5.x + run docker exec -u docker "$NAME" bash -lc 'ruby --version | grep "ruby 2.5"' [[ ${status} == 0 ]] unset output @@ -475,6 +440,10 @@ _healthcheck_wait () @test "Check Pantheon integration" { [[ $SKIP == 1 ]] && skip + # Terminus does not yet support PHP 8.0 + # See https://github.com/pantheon-systems/terminus/issues/2113 + [[ "${VERSION}" == "8.0" ]] && skip + # Confirm secret is not empty [[ "${SECRET_TERMINUS_TOKEN}" != "" ]] @@ -581,28 +550,6 @@ _healthcheck_wait () make clean } -@test "Check Drush Backdrop Commands" { - [[ $SKIP == 1 ]] && skip - # Skip until Drush Backdrop is compatible with PHP 7.4 - [[ "$VERSION" == "7.4" ]] && skip - - ### Setup ### - make start - - run _healthcheck_wait - unset output - - ### Tests ### - - # Check Drush Backdrop command loaded - run docker exec -u docker "$NAME" bash -lc 'drush help backdrop-core-status' - [[ "${output}" =~ "Provides a birds-eye view of the current Backdrop installation, if any." ]] - unset output - - ### Cleanup ### - make clean -} - @test "VS Code Server" { [[ $SKIP == 1 ]] && skip