Skip to content

Commit 10f41bc

Browse files
committed
Initial commit.
0 parents  commit 10f41bc

35 files changed

Lines changed: 4349 additions & 0 deletions
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
version: "3.9"
2+
services:
3+
${APP_NAME}:
4+
image: ghcr.io/${IMAGE_REPO}:${RELEASE_VERSION}
5+
restart: always
6+
network_mode: bridge
7+
ports:
8+
- "80"
9+
environment:
10+
VIRTUAL_HOST: ${HOST_DOMAIN}
11+
LETSENCRYPT_HOST: ${HOST_DOMAIN}
12+
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL}
13+
volumes:
14+
- ${APP_NAME}-mydb:/app/App_Data
15+
${APP_NAME}-migration:
16+
image: ghcr.io/${IMAGE_REPO}:${RELEASE_VERSION}
17+
restart: "no"
18+
profiles:
19+
- migration
20+
command: --AppTasks=migrate
21+
volumes:
22+
- ${APP_NAME}-mydb:/app/App_Data
23+
24+
volumes:
25+
${APP_NAME}-mydb:

.deploy/nginx-proxy-compose.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
version: '2'
2+
3+
services:
4+
nginx-proxy:
5+
image: jwilder/nginx-proxy
6+
container_name: nginx-proxy
7+
restart: always
8+
ports:
9+
- "80:80"
10+
- "443:443"
11+
volumes:
12+
- conf:/etc/nginx/conf.d
13+
- vhost:/etc/nginx/vhost.d
14+
- html:/usr/share/nginx/html
15+
- dhparam:/etc/nginx/dhparam
16+
- certs:/etc/nginx/certs:ro
17+
- /var/run/docker.sock:/tmp/docker.sock:ro
18+
network_mode: bridge
19+
20+
letsencrypt:
21+
image: jrcs/letsencrypt-nginx-proxy-companion:2.0
22+
container_name: nginx-proxy-le
23+
restart: always
24+
environment:
25+
- DEFAULT_EMAIL=you@example.com
26+
volumes_from:
27+
- nginx-proxy
28+
volumes:
29+
- certs:/etc/nginx/certs:rw
30+
- acme:/etc/acme.sh
31+
- /var/run/docker.sock:/var/run/docker.sock:ro
32+
network_mode: bridge
33+
34+
volumes:
35+
conf:
36+
vhost:
37+
html:
38+
dhparam:
39+
certs:
40+
acme:

.github/workflows/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# ServiceStack mix GitHub Actions
2+
The `release.yml` in designed to help with CI deployment to a dedicated server with SSH access, Docker and Docker Compose.
3+
4+
## Overview
5+
A docker image is built and stored on GitHub's `ghcr.io` docker registry when a GitHub Release is created.
6+
7+
GitHub Actions specified in `release.yml` then copy files remotely via scp and use `docker-compose` to run the app remotely via SSH.
8+
9+
## Deployment server setup
10+
To get this working, a server needs to be setup with the following:
11+
12+
- SSH access
13+
- docker
14+
- docker-compose
15+
- ports 443 and 80 for web access of your hosted application
16+
17+
This can be your own server or any cloud hosted server like Digital Ocean, AWS, Azure etc.
18+
19+
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.
20+
21+
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.
22+
23+
For example, once copied to remote `~/nginx-proxy-compose.yml`, the following command can be run on the remote server.
24+
25+
```
26+
docker-compose -f ~/nginx-proxy-compose.yml up -d
27+
```
28+
29+
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.
30+
31+
## GitHub Repository setup
32+
The `release.yml` uses the following secrets.
33+
34+
- DEPLOY_HOST - hostname used to SSH to, this can either be an IP address or subdomain with A record pointing to the server.
35+
- DEPLOY_PORT - SSH port, usually `22`.
36+
- DEPLOY_USERNAME - the username being logged into via SSH. Eg, `ubuntu`, `ec2-user`, `root` etc.
37+
- DEPLOY_KEY - SSH private key used to remotely access deploy server/app host.
38+
- LETSENCRYPT_EMAIL - Email address, required for Let's Encrypt automated TLS certificates.
39+
40+
These secrets can use the [GitHub CLI](https://cli.github.com/manual/gh_secret_set) for ease of creation.
41+
42+
These secrets are used to populate variables within GitHub Actions and other configuration files.
43+
44+
## What's the process of `release.yml`?
45+
46+
![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/mix/release-ghr-vanilla-diagram.png)

.github/workflows/build.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Build
2+
3+
on:
4+
pull_request: {}
5+
push:
6+
branches:
7+
- '**' # matches every branch
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-20.04
12+
steps:
13+
- name: checkout
14+
uses: actions/checkout@v2.0.0
15+
16+
- name: setup .net core
17+
uses: actions/setup-dotnet@v1.7.2
18+
with:
19+
dotnet-version: 6.0.100
20+
21+
- name: build
22+
run: dotnet build
23+
working-directory: .
24+
25+
- name: test
26+
run: |
27+
dotnet test
28+
if [ $? -eq 0 ]; then
29+
echo TESTS PASSED
30+
else
31+
echo TESTS FAILED
32+
exit 1
33+
fi
34+
working-directory: ./ExampleDataApis.Tests
35+

.github/workflows/release.yml

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
name: Release
2+
permissions:
3+
packages: write
4+
contents: write
5+
on:
6+
# Triggered on new GitHub Release
7+
release:
8+
types: [published]
9+
# Triggered on every successful Build action
10+
workflow_run:
11+
workflows: ["Build"]
12+
branches: [main,master]
13+
types:
14+
- completed
15+
# Manual trigger for rollback to specific release or redeploy latest
16+
workflow_dispatch:
17+
inputs:
18+
version:
19+
default: latest
20+
description: Tag you want to release.
21+
required: true
22+
23+
jobs:
24+
push_to_registry:
25+
runs-on: ubuntu-20.04
26+
if: ${{ github.event.workflow_run.conclusion != 'failure' }}
27+
steps:
28+
# Checkout latest or specific tag
29+
- name: checkout
30+
if: ${{ github.event.inputs.version == '' || github.event.inputs.version == 'latest' }}
31+
uses: actions/checkout@v2
32+
- name: checkout tag
33+
if: ${{ github.event.inputs.version != '' && github.event.inputs.version != 'latest' }}
34+
uses: actions/checkout@v2
35+
with:
36+
ref: refs/tags/${{ github.event.inputs.version }}
37+
38+
# Assign environment variables used in subsequent steps
39+
- name: Env variable assignment
40+
run: echo "image_repository_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
41+
# TAG_NAME defaults to 'latest' if not a release or manual deployment
42+
- name: Assign version
43+
run: |
44+
echo "TAG_NAME=latest" >> $GITHUB_ENV
45+
if [ "${{ github.event.release.tag_name }}" != "" ]; then
46+
echo "TAG_NAME=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
47+
fi;
48+
if [ "${{ github.event.inputs.version }}" != "" ]; then
49+
echo "TAG_NAME=${{ github.event.inputs.version }}" >> $GITHUB_ENV
50+
fi;
51+
52+
- name: Login to GitHub Container Registry
53+
uses: docker/login-action@v1
54+
with:
55+
registry: ghcr.io
56+
username: ${{ github.repository_owner }}
57+
password: ${{ secrets.GITHUB_TOKEN }}
58+
59+
# Build and push new docker image, skip for manual redeploy other than 'latest'
60+
- name: Build and push Docker images
61+
uses: docker/build-push-action@v2.2.2
62+
if: ${{ github.event.inputs.version == '' || github.event.inputs.version == 'latest' }}
63+
with:
64+
file: Dockerfile
65+
context: .
66+
push: true
67+
tags: ghcr.io/${{ env.image_repository_name }}:${{ env.TAG_NAME }}
68+
69+
deploy_via_ssh:
70+
needs: push_to_registry
71+
runs-on: ubuntu-20.04
72+
if: ${{ github.event.workflow_run.conclusion != 'failure' }}
73+
steps:
74+
# Checkout latest or specific tag
75+
- name: checkout
76+
if: ${{ github.event.inputs.version == '' || github.event.inputs.version == 'latest' }}
77+
uses: actions/checkout@v2
78+
- name: checkout tag
79+
if: ${{ github.event.inputs.version != '' && github.event.inputs.version != 'latest' }}
80+
uses: actions/checkout@v2
81+
with:
82+
ref: refs/tags/${{ github.event.inputs.version }}
83+
84+
- name: repository name fix and env
85+
run: |
86+
echo "image_repository_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
87+
echo "domain=${{ secrets.DEPLOY_HOST }}" >> $GITHUB_ENV
88+
echo "letsencrypt_email=${{ secrets.LETSENCRYPT_EMAIL }}" >> $GITHUB_ENV
89+
echo "TAG_NAME=latest" >> $GITHUB_ENV
90+
if [ "${{ github.event.release.tag_name }}" != "" ]; then
91+
echo "TAG_NAME=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
92+
fi;
93+
if [ "${{ github.event.inputs.version }}" != "" ]; then
94+
echo "TAG_NAME=${{ github.event.inputs.version }}" >> $GITHUB_ENV
95+
fi;
96+
97+
# Populate docker-compose.yml with variables from build process, including TAG_NAME.
98+
- name: docker-compose file prep
99+
uses: danielr1996/envsubst-action@1.0.0
100+
env:
101+
RELEASE_VERSION: ${{ env.TAG_NAME }}
102+
IMAGE_REPO: ${{ env.image_repository_name }}
103+
APP_NAME: ${{ github.event.repository.name }}
104+
HOST_DOMAIN: ${{ env.domain }}
105+
LETSENCRYPT_EMAIL: ${{ env.letsencrypt_email }}
106+
with:
107+
input: .deploy/docker-compose-template.yml
108+
output: .deploy/${{ github.event.repository.name }}-docker-compose.yml
109+
110+
# Copy only the docker-compose.yml to remote server home folder
111+
- name: copy compose file via scp
112+
uses: appleboy/scp-action@v0.1.1
113+
with:
114+
host: ${{ secrets.DEPLOY_HOST }}
115+
username: ${{ secrets.DEPLOY_USERNAME }}
116+
port: ${{ secrets.DEPLOY_PORT }}
117+
key: ${{ secrets.DEPLOY_KEY }}
118+
source: ".deploy/${{ github.event.repository.name }}-docker-compose.yml"
119+
target: "~/"
120+
- name: Run remote db migrations
121+
uses: appleboy/ssh-action@v0.1.4
122+
env:
123+
APPTOKEN: ${{ secrets.GITHUB_TOKEN }}
124+
USERNAME: ${{ secrets.DEPLOY_USERNAME }}
125+
with:
126+
host: ${{ secrets.DEPLOY_API }}
127+
username: ${{ secrets.DEPLOY_USERNAME }}
128+
key: ${{ secrets.DEPLOY_KEY }}
129+
port: 22
130+
envs: APPTOKEN,USERNAME
131+
script: |
132+
echo $APPTOKEN | docker login ghcr.io -u $USERNAME --password-stdin
133+
docker-compose -f ~/.deploy/${{ github.event.repository.name }}-docker-compose.yml pull
134+
docker-compose -f ~/.deploy/${{ github.event.repository.name }}-docker-compose.yml up ${{ github.event.repository.name }}-migration
135+
136+
# Deploy Docker image with ServiceStack application using `docker compose up` remotely
137+
- name: remote docker-compose up via ssh
138+
uses: appleboy/ssh-action@v0.1.4
139+
env:
140+
APPTOKEN: ${{ secrets.GITHUB_TOKEN }}
141+
USERNAME: ${{ secrets.DEPLOY_USERNAME }}
142+
with:
143+
host: ${{ secrets.DEPLOY_HOST }}
144+
username: ${{ secrets.DEPLOY_USERNAME }}
145+
key: ${{ secrets.DEPLOY_KEY }}
146+
port: ${{ secrets.DEPLOY_PORT }}
147+
envs: APPTOKEN,USERNAME
148+
script: |
149+
echo $APPTOKEN | docker login ghcr.io -u $USERNAME --password-stdin
150+
docker-compose -f ~/.deploy/${{ github.event.repository.name }}-docker-compose.yml pull
151+
docker-compose -f ~/.deploy/${{ github.event.repository.name }}-docker-compose.yml up -d

0 commit comments

Comments
 (0)