diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3c6dbaeda..50db034ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,11 +12,9 @@ on: env: DOTNET_NOLOGO: true jobs: - release: + windows-standalone: if: ${{ github.actor != 'dependabot[bot]' }} runs-on: windows-2022 - outputs: - version: ${{ steps.save-version.outputs.version }} steps: - name: Check for secrets env: @@ -38,18 +36,9 @@ jobs: - name: Build Frontend run: .\build.ps1 working-directory: src/ServicePulse.Host - - name: Run component tests - run: npm run test:component - working-directory: src/Frontend - - name: Run application tests - run: npm run test:application - working-directory: src/Frontend # .NET Build and sign - name: Build run: dotnet build src --configuration Release - - id: save-version - name: Save version - run: echo "version=${{env.MinVerVersion}}" >> $env:GITHUB_OUTPUT - name: Sign NuGet packages uses: Particular/sign-nuget-packages-action@v1.0.0 with: @@ -107,19 +96,9 @@ jobs: uses: Particular/push-octopus-package-action@main with: octopus-deploy-api-key: ${{ secrets.OCTOPUS_DEPLOY_API_KEY }} - docker: - needs: release - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - - os: windows-2019 - image-name: servicepulse-windows - dockerfile: dockerfile.iis - - os: ubuntu-20.04 - image-name: servicepulse - dockerfile: dockerfile.nginx - fail-fast: false + linux-container: + if: ${{ github.actor != 'dependabot[bot]' }} + runs-on: ubuntu-22.04 steps: - name: Check for secrets env: @@ -130,30 +109,39 @@ jobs: uses: actions/checkout@v4.1.6 with: fetch-depth: 0 + - name: Install MinVer CLI + run: dotnet tool install --global minver-cli + - name: Determine version + run: echo "MinVerVersion=$(minver)" >> $GITHUB_ENV - name: Set up Node.js uses: actions/setup-node@v4.0.2 with: node-version: 21.6.x - # Build Frontend - name: Build Frontend run: .\build.ps1 - shell: pwsh working-directory: src/ServicePulse.Host - - name: Update app.constants.js + shell: pwsh + - name: Update app.constants.js with MinVerVersion run: | $filename = "src/ServicePulse.Host/app/js/app.constants.js" - (Get-Content $filename).replace("1.2.0", "${{ needs.release.outputs.version }}") | Set-Content $filename + (Get-Content $filename).replace("1.2.0", "${{ env.MinVerVersion }}") | Set-Content $filename shell: pwsh - - name: Build Docker image - if: ${{ matrix.image-name == 'servicepulse' || (github.event_name == 'push' && github.ref_type == 'tag') }} - run: docker build -t particular/${{ matrix.image-name }}:${{ needs.release.outputs.version }} -f ${{ matrix.dockerfile }} . - working-directory: src - - name: Login to Docker Hub - if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }} - uses: docker/login-action@v3.1.0 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Push Docker image - if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }} - run: docker push particular/${{ matrix.image-name }}:${{ needs.release.outputs.version }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.3.0 + - name: Pull nginx:stable-alpine and determine digest + run: | + docker pull nginx:stable-alpine + echo "NGINX_DIGEST=$(docker inspect -f json nginx:stable-alpine | jq -r .[0].RepoDigests[0] | cut -d@ -f2)" >> $GITHUB_ENV + - name: Log in to GitHub container registry + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + - name: Build & inspect image + env: + TAG_NAME: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.number) || env.MinVerVersion }} + run: | + docker buildx build --push --tag ghcr.io/particular/servicepulse:${{ env.TAG_NAME }} --file src/Container/Dockerfile \ + --build-arg NGINX_TAGORDIGEST="@${{ env.NGINX_DIGEST }}" \ + --build-arg VERSION=${{ env.MinVerVersion }} \ + --build-arg GITHUB_SHA=${{ github.sha }} \ + --build-arg GITHUB_REF_NAME=${{ github.ref.name }} \ + --platform linux/arm64,linux/arm,linux/amd64 . + docker buildx imagetools inspect ghcr.io/particular/servicepulse:${{ env.TAG_NAME }} \ No newline at end of file diff --git a/README.md b/README.md index 4cd1db03d..b200b42dd 100644 --- a/README.md +++ b/README.md @@ -135,34 +135,6 @@ ServicePulse is supported on the following desktop browser versions: - Firefox ESR [current version](https://www.mozilla.org/en-US/firefox/enterprise/) - Safari [latest major version](https://developer.apple.com/safari/) -## Docker image deployment +## Container image development -Dockerfiles for ServicePulse resides within the [`src`](https://github.com/Particular/ServicePulse/tree/master/src) folder. There are 2 docker files: - -- 1 for a [Windows image](https://github.com/Particular/ServicePulse/blob/master/src/dockerfile.iis) -- 1 for a [Linux image](https://github.com/Particular/ServicePulse/blob/master/src/dockerfile.nginx) - -### Building & staging docker images - -The docker files are all built as part of the [release workflow](https://github.com/Particular/ServicePulse/blob/master/.github/workflows/release.yml), pushed to the Docker hub, and tagged with the version of ServicePulse being deployed. More details are available in the [documentation](https://docs.particular.net/servicepulse/containerization/). - -For example, If we were deploying version 1.30.1 of ServicePulse, the build configurations after the Deploy step will build the following 2 containers for ServicePulse and tag them `1.30.1`: - -- `particular/servicepulse:1.30.1` -- `particular/servicepule-windows:1.30.1` - -These images are tagged with the specific version of ServicePulse being built and pushed to the corresponding public `particular/servicepulse{-os}` repositories. At this point, the docker images are considered staged. If someone is watching the feed directly, they can install the staged images by explicitly specifying the exact tag, e.g., `docker pull particular/servicepulse:1.30.1`. - -### Promoting docker images to production - -When a ServicePulse release is promoted to production, one of the steps is to take the staged images and re-tag them as the following: - -- `particular/servicepulse:1.30.1` => `particular/servicepulse:1` - - This is so that customers interested in updates within a major can install the specific major only and not worry about breaking changes between major versions being automatically rolled out. Useful for auto-upgrading containers in a _production_ environment. -- `particular/servicepulse:1.30.1` => `particular/servicepulse:latest` - - Primarily for developers wanting to use the latest version (`docker-compose up -d --build --force-recreate --renew-anon-volumes` - - This is only true if the release's major version is the same as the current latest major version. - - If a fix is being backported to a previous major, then the `:latest` tag will not be updated. - - If a release targets the current latest major or is a new major after the previous latest, then the `:latest` tag is updated to match the version being released. - -Once the tagging has been completed, the images are considered to be publicly released. +A Dockerfile for ServicePulse resides within the [`src/Container`](https://github.com/Particular/ServicePulse/tree/master/src/Container) folder. The container images are all built as part of the [release workflow](https://github.com/Particular/ServicePulse/blob/master/.github/workflows/release.yml) and staged in the [Github Container Registry](https://github.com/Particular/ServicePulse/pkgs/container/servicepulse). For branches with PRs the image will be tagged with the pr number, e.g. `pr-1234`. diff --git a/src/Container/Dockerfile b/src/Container/Dockerfile new file mode 100644 index 000000000..08447548c --- /dev/null +++ b/src/Container/Dockerfile @@ -0,0 +1,39 @@ +ARG NGINX_TAGORDIGEST=":stable-alpine" +FROM nginx$NGINX_TAGORDIGEST + +ARG VERSION +ARG GITHUB_SHA +ARG GITHUB_REF_NAME + +LABEL org.opencontainers.image.title="ServicePulse" \ + org.opencontainers.image.description="ServicePulse provides real-time production monitoring for distributed applications. It monitors the health of a system's endpoints, detects processing errors, sends failed messages for reprocessing, and ensures the specific environment's needs are met, all in one consolidated dashboard." \ + org.opencontainers.image.authors="Particular Software" \ + org.opencontainers.image.vendor="Particular Software" \ + org.opencontainers.image.source="https://github.com/particular/servicepulse" \ + org.opencontainers.image.documentation="https://github.com/Particular/ServicePulse/blob/master/src/Container/README.md" \ + org.opencontainers.image.licenses="Commercial OR RPL-1.5" \ + org.opencontainers.image.version=$VERSION \ + org.opencontainers.image.revision=$GITHUB_SHA \ + org.opencontainers.image.base.digest=$NGINX_TAGORDIGEST \ + org.opencontainers.image.base.name="nginx:stable-alpine" \ + com.particular.github.ref.name=$GITHUB_REF_NAME \ + com.particular.support.url="https://particular.net/support" \ + maintainer="Particular Software" + +ENV SERVICECONTROL_URL="http://localhost:33333/api/" +ENV MONITORING_URLS="['http://localhost:33633/']" +ENV BASE_URL="/" + +COPY /src/ServicePulse.Host/app /usr/share/nginx/html + +RUN mv /usr/share/nginx/html/js/app.constants.js /usr/share/nginx/html/js/app.constants.template &&\ + sed -i \ + -e "s,http://localhost:33333/api/,\$SERVICECONTROL_URL,g" \ + -e "s,\['http://localhost:33633/'\],\$MONITORING_URLS,g" \ + -e "s,'/','\$BASE_URL',g" \ + /usr/share/nginx/html/js/app.constants.template + +ADD /src/Container/nginx.conf /etc/nginx/ +ADD --chown=root:root --chmod=755 /src/Container/updateconstants.sh /docker-entrypoint.d/40-update-servicepulse-constants.sh + +EXPOSE 90 \ No newline at end of file diff --git a/src/Container/README.md b/src/Container/README.md new file mode 100644 index 000000000..dc4052378 --- /dev/null +++ b/src/Container/README.md @@ -0,0 +1,80 @@ +# ServicePulse + +This document describes basic usage and information related to the ServicePulse image. The complete documentation of ServicePulse the application can be found on the [Particular Software documentation site](https://docs.particular.net/servicepulse/). + +## Usage + +The following is the most basic way to create a ServicePulse container using [Docker](https://www.docker.com/): + +```shell +docker run -p 9090:90 particular/servicepulse:latest +``` + +### Environment Variables + +- **`SERVICECONTROL_URL`**: _Default_: `http://localhost:33333/api/`. The url to your ServiceControl instance +- **`MONITORING_URLS`**: _Default_: `['http://localhost:33633/']`. A JSON array of URLs to your monitoring instances +- **`BASE_URL`**: _Default_ `'/'`. The base path to your ServicePulse install, for reverse proxy installations. + +It may be desireable to run the ServiceControl services in an isolated network. When doing so ServicePulse must be configured to connect to those services using environment variables: + +```shell +docker run -p 9090:90 -e SERVICECONTROL_URL="http://servicecontrol:33333/api/" -e MONITORING_URLS="['http://servicecontrol-monitoring:33633']" particular/servicepulse:latest +``` + +Or as part of a https://docs.docker.com/compose/compose-file/05-services/: + +```yaml +services: + servicepulse: + ports: + - 9090:90 + environment: + - SERVICECONTROL_URL=http://servicecontrol:33333/api/ + - MONITORING_URLS=['http://servicecontrol-monitoring:33633'] + image: particular/servicepulse:latest +``` + +### Image tagging + +#### `latest` tag + +This tag is primarily for developers wanting to use the latest version, e.g. `docker-compose up -d --build --force-recreate --renew-anon-volumes`. + +If a release targets the current latest major or is a new major after the previous latest, then the `:latest` tag applied to the image pushed to [Docker Hub](https://hub.docker.com/r/particular/servicepulse). + +If the release is a patch release to a previous major, then the `:latest` tag will not be added to the image pushed to Docker Hub. + +The `:latest` tag is never added to images pushed to [the GitHub Container Registry](https://github.com/Particular/ServicePulse/pkgs/container/servicepulse). + +#### Version tags + +We use [SemVer](http://semver.org/) for versioning. Release images pushed to [Docker Hub](https://hub.docker.com/r/particular/servicepulse) will be tagged with the release version. Staged images pushed to [the GitHub Container Registry](https://github.com/Particular/ServicePulse/pkgs/container/servicepulse) will not have a version tag. + +#### Pull request tag + +Pre-release image versions generated from [GitHub pull requests](https://github.com/Particular/ServicePulse/pulls) will only be available in the GitHub Container Registry and are tagged using the pull request number using the following convention: `pr-1234`. The pull request tag is only added to images pushed to [the GitHub Container Registry](https://github.com/Particular/ServicePulse/pkgs/container/servicepulse) and are not added to images pushed to [Docker Hub](https://hub.docker.com/r/particular/servicepulse). + +#### Major version tag + +The latest release within a major version will be tagged with the major version number only on images pushed to [Docker Hub](https://hub.docker.com/r/particular/servicepulse). This allows users to target a specific major version to help avoid the risk of incurring breaking changes between major versions. Useful for auto-upgrading containers in a _production_, for instance: + +If `particular/servicepulse:1.30.1` is the latest release in the version 1 major release, the image will also be tagged `particular/servicepulse:1`. + +The major version tag is never added to images pushed to [the GitHub Container Registry](https://github.com/Particular/ServicePulse/pkgs/container/servicepulse). + +## Built With + +This image is built from the stable Alpine version of the [nginx official Docker image](https://hub.docker.com/_/nginx/). + +## Contributing + +Please read [our documentation](https://docs.particular.net/platform/contributing) for details on how to contribute to Particular Software projects. + +## Authors + +This software, including this container image, is built and maintained by the team at [Particular Software](https://particular.net). See also the list of [contributors](https://github.com/Particular/ServicePulse/graphs/contributors) who participated in this project. + +## License + +This project is licensed under the Reciprocal Public License 1.5 (RPL1.5) and commercial licenses are available - see the [LICENSE.md](https://github.com/Particular/ServicePulse/blob/master/LICENSE.md) file for details. \ No newline at end of file diff --git a/src/nginx.conf b/src/Container/nginx.conf similarity index 100% rename from src/nginx.conf rename to src/Container/nginx.conf diff --git a/src/Container/updateconstants.sh b/src/Container/updateconstants.sh new file mode 100644 index 000000000..c2cdfd507 --- /dev/null +++ b/src/Container/updateconstants.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +if [ ! -f /usr/share/nginx/html/js/app.constants.js ] +then + envsubst < /usr/share/nginx/html/js/app.constants.template > /usr/share/nginx/html/js/app.constants.js +fi \ No newline at end of file diff --git a/src/builddockerimages.ps1 b/src/builddockerimages.ps1 deleted file mode 100644 index 7c2b92363..000000000 --- a/src/builddockerimages.ps1 +++ /dev/null @@ -1,8 +0,0 @@ -cd ServicePulse.Host -npm install -node ./node_modules/webpack/bin/webpack.js --config app/modules/modules.webpackconfig.builder.js - -cd .. - -docker build -f .\dockerfile.iis -t particular/servicepulse.iis . -docker build -f .\dockerfile.nginx -t particular/servicepulse.nginx . \ No newline at end of file diff --git a/src/dockerfile.iis b/src/dockerfile.iis deleted file mode 100644 index ac1537ade..000000000 --- a/src/dockerfile.iis +++ /dev/null @@ -1,15 +0,0 @@ -FROM mcr.microsoft.com/windows/servercore/iis - -RUN powershell -NoProfile -Command Remove-Item -Recurse C:\inetpub\wwwroot\* - -WORKDIR /inetpub/wwwroot -COPY ServicePulse.Host/app/ . - -SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] - -COPY iis.config /inetpub/wwwroot/web.config - -# Install IIS Rewrite Module -WORKDIR /install -ADD https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi rewrite_amd64_en-US.msi -RUN Write-Host 'Installing URL Rewrite' ; Start-Process msiexec.exe -ArgumentList '/i', 'rewrite_amd64_en-US.msi', '/quiet', '/norestart' -NoNewWindow -Wait; diff --git a/src/dockerfile.nginx b/src/dockerfile.nginx deleted file mode 100644 index 0741b929f..000000000 --- a/src/dockerfile.nginx +++ /dev/null @@ -1,19 +0,0 @@ -FROM ubuntu:latest - -USER root - -RUN apt-get update -RUN apt-get install -y nginx nodejs - -RUN rm -v /etc/nginx/nginx.conf - -ADD nginx.conf /etc/nginx/ - -ADD ServicePulse.Host/app /usr/share/nginx/html/ -ADD ServicePulse.Host/app /var/www/html/ - -RUN echo "daemon off;" >> /etc/nginx/nginx.conf - -EXPOSE 90 - -CMD ["/usr/sbin/nginx"] \ No newline at end of file diff --git a/src/iis.config b/src/iis.config deleted file mode 100644 index 7a22f8e49..000000000 --- a/src/iis.config +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file