-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #40 from NetCoreTemplates/sync-gh-actions
Update for sync-gh-actions
- Loading branch information
Showing
14 changed files
with
194 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
version: "3.9" | ||
services: | ||
app: | ||
image: ghcr.io/${IMAGE_REPO}:${RELEASE_VERSION} | ||
restart: always | ||
ports: | ||
- "8080" | ||
container_name: ${APP_NAME}_app | ||
environment: | ||
VIRTUAL_HOST: ${HOST_DOMAIN} | ||
VIRTUAL_PORT: 8080 # New default ASP.NET port -> https://learn.microsoft.com/en-us/dotnet/core/compatibility/containers/8.0/aspnet-port | ||
LETSENCRYPT_HOST: ${HOST_DOMAIN} | ||
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL} | ||
volumes: | ||
- app-mydb:/app/App_Data | ||
|
||
networks: | ||
default: | ||
external: true | ||
name: nginx | ||
|
||
volumes: | ||
app-mydb: |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,99 @@ | ||
# ServiceStack mix GitHub Actions | ||
The `release.yml` in designed to help with CI deployment to a dedicated server with SSH access, Docker and Docker Compose. | ||
|
||
## Overview | ||
A docker image is built and stored on GitHub's `ghcr.io` docker registry when a GitHub Release is created. | ||
|
||
GitHub Actions specified in `release.yml` then copy files remotely via scp and use `docker-compose` to run the app remotely via SSH. | ||
|
||
## Deployment server setup | ||
To get this working, a server needs to be setup with the following: | ||
|
||
- SSH access | ||
- docker | ||
- docker-compose | ||
- ports 443 and 80 for web access of your hosted application | ||
|
||
This can be your own server or any cloud hosted server like Digital Ocean, AWS, Azure etc. | ||
|
||
When setting up your server, you'll want to use a dedicated SSH key for access to be used by GitHub Actions. GitHub Actions will need the *private* SSH key within a GitHub Secret to authenticate. This can be done via ssh-keygen and copying the public key to the authorized clients on the server. | ||
|
||
To let your server handle multiple ServiceStack applications and automate the generation and management of TLS certificates, an additional docker-compose file is provided via the `x mix` template, `nginx-proxy-compose.yml`. This docker-compose file is ready to run and can be copied to the deployment server. | ||
|
||
For example, once copied to remote `~/nginx-proxy-compose.yml`, the following command can be run on the remote server. | ||
|
||
``` | ||
docker-compose -f ~/nginx-proxy-compose.yml up -d | ||
``` | ||
|
||
This will run an nginx reverse proxy along with a companion container that will watch for additional containers in the same docker network and attempt to initialize them with valid TLS certificates. | ||
|
||
## GitHub Repository setup | ||
The `release.yml` uses the following secrets. | ||
|
||
- DEPLOY_HOST - hostname used to SSH to, this can either be an IP address or subdomain with A record pointing to the server. | ||
- DEPLOY_USERNAME - the username being logged into via SSH. Eg, `ubuntu`, `ec2-user`, `root` etc. | ||
- DEPLOY_KEY - SSH private key used to remotely access deploy server/app host. | ||
- LETSENCRYPT_EMAIL - Email address, required for Let's Encrypt automated TLS certificates. | ||
|
||
These secrets can use the [GitHub CLI](https://cli.github.com/manual/gh_secret_set) for ease of creation. | ||
|
||
These secrets are used to populate variables within GitHub Actions and other configuration files. | ||
|
||
## What's the process of `release.yml`? | ||
|
||
![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/mix/release-ghr-vanilla-diagram.png) | ||
## Overview | ||
|
||
This template uses the deployment configurations for a ServiceStack .NET 8 application. The application is containerized using Docker and is set up to be automatically built and deployed via GitHub Actions. The recommended deployment target is a stand-alone Linux server running Ubuntu, with an NGINX reverse proxy also containerized using Docker, which a Docker Compose file is included in the template under the `.deploy` directory. | ||
|
||
### Highlights | ||
- 🌐 **NGINX Reverse Proxy**: Utilizes an NGINX reverse proxy to handle web traffic and SSL termination. | ||
- 🚀 **GitHub Actions**: Leverages GitHub Actions for CI/CD, pushing Docker images to GitHub Container Registry and deploying them on a remote server. | ||
- 🐳 **Dockerized ServiceStack App**: The application is containerized, with the image built using `.NET 8`. | ||
- 🔄 **Automated Migrations**: Includes a separate service for running database migrations. | ||
|
||
### Technology Stack | ||
- **Web Framework**: ServiceStack | ||
- **Language**: C# (.NET 8) | ||
- **Containerization**: Docker | ||
- **Reverse Proxy**: NGINX | ||
- **CI/CD**: GitHub Actions | ||
- **OS**: Ubuntu 22.04 (Deployment Server) | ||
|
||
|
||
|
||
## Deployment Server Setup | ||
|
||
To successfully host your ServiceStack applications, there are several components you need to set up on your deployment server. This guide assumes you're working on a standalone Linux server (Ubuntu is recommended) with SSH access enabled. | ||
|
||
### Prerequisites | ||
|
||
1. **SSH Access**: Required for GitHub Actions to communicate with your server. | ||
2. **Docker**: To containerize your application. | ||
3. **Docker-Compose**: For orchestrating multiple containers. | ||
4. **Ports**: 80 and 443 should be open for web access. | ||
5. **nginx-reverse-proxy**: For routing traffic to multiple ServiceStack applications and managing TLS certificates. | ||
|
||
You can use any cloud-hosted or on-premises server like Digital Ocean, AWS, Azure, etc., for this setup. | ||
|
||
### Step-by-Step Guide | ||
|
||
#### 1. Install Docker and Docker-Compose | ||
|
||
It is best to follow the [latest installation instructions on the Docker website](https://docs.docker.com/engine/install/ubuntu/) to ensure to have the correct setup with the latest patches. | ||
|
||
#### 2. Configure SSH for GitHub Actions | ||
|
||
Generate a dedicated SSH key pair to be used by GitHub Actions: | ||
|
||
```bash | ||
ssh-keygen -t rsa -b 4096 -f ~/.ssh/github_actions | ||
``` | ||
|
||
Add the public key to the `authorized_keys` file on your server: | ||
|
||
```bash | ||
cat ~/.ssh/github_actions.pub >> ~/.ssh/authorized_keys | ||
``` | ||
|
||
Then, add the *private* key to your GitHub Secrets as `DEPLOY_KEY` to enable GitHub Actions to SSH into the server securely. | ||
|
||
#### 3. Set Up nginx-reverse-proxy | ||
|
||
You should have a `docker-compose` file similar to the `nginx-proxy-compose.yml` in your repository. Upload this file to your server: | ||
|
||
```bash | ||
scp nginx-proxy-compose.yml user@your_server:~/ | ||
``` | ||
|
||
To bring up the nginx reverse proxy and its companion container for handling TLS certificates, run: | ||
|
||
```bash | ||
docker compose -f ~/nginx-proxy-compose.yml up -d | ||
``` | ||
|
||
This will start an nginx reverse proxy along with a companion container. They will automatically watch for additional Docker containers on the same network and initialize them with valid TLS certificates. | ||
|
||
|
||
|
||
## GitHub Repository Setup | ||
|
||
Configuring your GitHub repository is an essential step for automating deployments via GitHub Actions. This guide assumes you have a `release.yml` workflow file in your repository's `.github/workflows/` directory, and your deployment server has been set up according to the [Deployment Server Setup](#Deployment-Server-Setup) guidelines. | ||
|
||
### Secrets Configuration | ||
|
||
Your GitHub Actions workflow requires the following secrets to be set in your GitHub repository: | ||
|
||
1. **`DEPLOY_HOST`**: The hostname for SSH access. This can be either an IP address or a domain with an A-record pointing to your server. | ||
2. **`DEPLOY_USERNAME`**: The username for SSH login. Common examples include `ubuntu`, `ec2-user`, or `root`. | ||
3. **`DEPLOY_KEY`**: The SSH private key to securely access the deployment server. This should be the same key you've set up on your server for GitHub Actions. | ||
4. **`LETSENCRYPT_EMAIL`**: Your email address, required for Let's Encrypt automated TLS certificates. | ||
|
||
#### Using GitHub CLI for Secret Management | ||
|
||
You can conveniently set these secrets using the [GitHub CLI](https://cli.github.com/manual/gh_secret_set) like this: | ||
|
||
```bash | ||
gh secret set DEPLOY_HOST --body="your-host-or-ip" | ||
gh secret set DEPLOY_USERNAME --body="your-username" | ||
gh secret set DEPLOY_KEY --bodyFile="path/to/your/ssh-private-key" | ||
gh secret set LETSENCRYPT_EMAIL --body="[email protected]" | ||
``` | ||
|
||
These secrets will populate environment variables within your GitHub Actions workflow and other configuration files, enabling secure and automated deployment of your ServiceStack applications. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,7 +34,7 @@ jobs: | |
uses: actions/checkout@v3 | ||
with: | ||
ref: refs/tags/${{ github.event.inputs.version }} | ||
|
||
# Assign environment variables used in subsequent steps | ||
- name: Env variable assignment | ||
run: echo "image_repository_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV | ||
|
@@ -48,24 +48,44 @@ jobs: | |
if [ "${{ github.event.inputs.version }}" != "" ]; then | ||
echo "TAG_NAME=${{ github.event.inputs.version }}" >> $GITHUB_ENV | ||
fi; | ||
if [ ! -z "${{ secrets.APPSETTINGS_PATCH }}" ]; then | ||
echo "HAS_APPSETTINGS_PATCH=true" >> $GITHUB_ENV | ||
else | ||
echo "HAS_APPSETTINGS_PATCH=false" >> $GITHUB_ENV | ||
fi; | ||
- name: Login to GitHub Container Registry | ||
uses: docker/login-action@v2 | ||
with: | ||
registry: ghcr.io | ||
username: ${{ github.actor }} | ||
password: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
|
||
- name: Setup dotnet | ||
uses: actions/setup-dotnet@v3 | ||
with: | ||
dotnet-version: '8.0' | ||
|
||
- name: Install x tool | ||
if: env.HAS_APPSETTINGS_PATCH == 'true' | ||
run: dotnet tool install -g x | ||
|
||
- name: Apply Production AppSettings | ||
if: env.HAS_APPSETTINGS_PATCH == 'true' | ||
working-directory: ./MyApp | ||
run: | | ||
cat <<EOF >> appsettings.json.patch | ||
${{ secrets.APPSETTINGS_PATCH }} | ||
EOF | ||
x patch appsettings.json.patch | ||
|
||
# Build and push new docker image, skip for manual redeploy other than 'latest' | ||
- name: Build and push Docker images | ||
uses: docker/build-push-action@v3 | ||
if: ${{ github.event.inputs.version == '' || github.event.inputs.version == 'latest' }} | ||
with: | ||
file: Dockerfile | ||
context: . | ||
push: true | ||
tags: ghcr.io/${{ env.image_repository_name }}:${{ env.TAG_NAME }} | ||
|
||
- name: Build and push Docker image | ||
run: | | ||
dotnet publish --os linux --arch x64 -c Release -p:ContainerRepository=${{ env.image_repository_name }} -p:ContainerRegistry=ghcr.io -p:ContainerImageTags=${{ env.TAG_NAME }} -p:ContainerPort=80 | ||
deploy_via_ssh: | ||
needs: push_to_registry | ||
runs-on: ubuntu-22.04 | ||
|
@@ -84,8 +104,6 @@ jobs: | |
- name: repository name fix and env | ||
run: | | ||
echo "image_repository_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV | ||
echo "domain=${{ secrets.DEPLOY_HOST }}" >> $GITHUB_ENV | ||
echo "letsencrypt_email=${{ secrets.LETSENCRYPT_EMAIL }}" >> $GITHUB_ENV | ||
echo "TAG_NAME=latest" >> $GITHUB_ENV | ||
if [ "${{ github.event.release.tag_name }}" != "" ]; then | ||
echo "TAG_NAME=${{ github.event.release.tag_name }}" >> $GITHUB_ENV | ||
|
@@ -97,14 +115,14 @@ jobs: | |
- name: Create .env file | ||
run: | | ||
echo "Generating .env file" | ||
echo "# Autogenerated .env file" > .env | ||
echo "HOST_DOMAIN=${{ secrets.DEPLOY_HOST }}" >> .env | ||
echo "LETSENCRYPT_EMAIL=${{ secrets.LETSENCRYPT_EMAIL }}" >> .env | ||
echo "APP_NAME=${{ github.event.repository.name }}" >> .env | ||
echo "IMAGE_REPO=${{ env.image_repository_name }}" >> .env | ||
echo "RELEASE_VERSION=${{ env.TAG_NAME }}" >> .env | ||
echo "# Autogenerated .env file" > .deploy/.env | ||
echo "HOST_DOMAIN=${{ secrets.DEPLOY_HOST }}" >> .deploy/.env | ||
echo "LETSENCRYPT_EMAIL=${{ secrets.LETSENCRYPT_EMAIL }}" >> .deploy/.env | ||
echo "APP_NAME=${{ github.event.repository.name }}" >> .deploy/.env | ||
echo "IMAGE_REPO=${{ env.image_repository_name }}" >> .deploy/.env | ||
echo "RELEASE_VERSION=${{ env.TAG_NAME }}" >> .deploy/.env | ||
# Copy only the docker-compose.yml to remote server home folder | ||
- name: copy files to target server via scp | ||
uses: appleboy/[email protected] | ||
|
@@ -113,10 +131,11 @@ jobs: | |
username: ${{ secrets.DEPLOY_USERNAME }} | ||
port: 22 | ||
key: ${{ secrets.DEPLOY_KEY }} | ||
source: "./docker-compose.yml,./docker-compose.prod.yml,./.env" | ||
strip_components: 2 | ||
source: "./.deploy/docker-compose.yml,./.deploy/.env" | ||
target: "~/.deploy/${{ github.event.repository.name }}/" | ||
|
||
- name: Run remote db migrations | ||
- name: Setup App_Data volume directory | ||
uses: appleboy/[email protected] | ||
env: | ||
APPTOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
@@ -128,10 +147,12 @@ jobs: | |
port: 22 | ||
envs: APPTOKEN,USERNAME | ||
script: | | ||
set -e | ||
echo $APPTOKEN | docker login ghcr.io -u $USERNAME --password-stdin | ||
cd ~/.deploy/${{ github.event.repository.name }} | ||
docker compose -f ./docker-compose.yml -f ./docker-compose.prod.yml pull | ||
docker compose -f ./docker-compose.yml -f ./docker-compose.prod.yml up app-migration | ||
docker compose pull | ||
export APP_ID=$(docker compose run --entrypoint "id -u" --rm app) | ||
docker compose run --entrypoint "chown $APP_ID:$APP_ID /app/App_Data" --user root --rm app | ||
# Deploy Docker image with your application using `docker compose up` remotely | ||
- name: remote docker-compose up via ssh | ||
|
@@ -148,5 +169,5 @@ jobs: | |
script: | | ||
echo $APPTOKEN | docker login ghcr.io -u $USERNAME --password-stdin | ||
cd ~/.deploy/${{ github.event.repository.name }} | ||
docker compose -f ./docker-compose.yml -f ./docker-compose.prod.yml pull | ||
docker compose -f ./docker-compose.yml -f ./docker-compose.prod.yml up app -d | ||
docker compose pull | ||
docker compose up app -d |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
## App Writable Folder | ||
|
||
This directory is designated for: | ||
|
||
- **Embedded Databases**: Such as SQLite. | ||
- **Writable Files**: Files that the application might need to modify during its operation. | ||
|
||
For applications running in **Docker**, it's a common practice to mount this directory as an external volume. This ensures: | ||
|
||
- **Data Persistence**: App data is preserved across deployments. | ||
- **Easy Replication**: Facilitates seamless data replication for backup or migration purposes. |
Oops, something went wrong.