Skip to content

Commit

Permalink
Added shallow Web template
Browse files Browse the repository at this point in the history
  • Loading branch information
vivet committed Aug 31, 2024
1 parent 2183e81 commit 3fc022c
Show file tree
Hide file tree
Showing 12 changed files with 430 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Web/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git
18 changes: 18 additions & 0 deletions Web/.github/config/slack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
username: GitHub Actions
icon_url: https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png

pretext: "{{icon jobStatus}} *<{{repositoryUrl}}|{{repositoryName}}>* <{{workflowRunUrl}}|`#{{runNumber}}`> triggered via {{eventName}} by *<https://github.com/{{actor}}|{{actor}}>* for branch <{{refUrl}}|`{{ref}}`>."

text: |
{{#if payload.commits}}
*Commits*
{{#each payload.commits}}
<{{this.url}}|`{{truncate this.id 8}}`> - {{this.message}}
{{/each}}
{{/if}}
footer: >-
<{{repositoryUrl}}|{{repositoryName}}> #{{runNumber}}
fallback: |-
[GitHub] {{workflow}} #{{runNumber}} {{jobName}} is {{jobStatus}}
145 changes: 145 additions & 0 deletions Web/.github/workflows/build-and-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
name: Build and Deploy
on:
push
env:
NODE_JS_VERSION: 20.16.0
APP_NAME: nano.template.web
IMAGE_NAME: nano.template.web
SERVICE_NAME: nano-template-web
VERSION: '${{ vars.VERSION }}.${{ github.run_number }}.${{ github.run_attempt }}'
AZURE_GROUP: Kubernetes
AZURE_LOCATION: North Europe
KUBERNETES_NAMESPACE: default
KUBERNETES_REPLICA_COUNT: ${{ github.ref == 'refs/heads/master' && 2 || 1 }}
KUBERNETES_REPLICA_COUNT_MAX: ${{ github.ref == 'refs/heads/master' && 2 || 1 }}
KUBERNETES_REPLICA_HISTORY_COUNT: 0
KUBERNETES_MEMORY_REQUEST: 372Mi
KUBERNETES_MEMORY_LIMIT: 1152Mi
KUBERNETES_MEMORY_SCALING: 180
KUBERNETES_CPU_REQUEST: 150m
KUBERNETES_CPU_LIMIT: 450m
KUBERNETES_CPU_SCALING: 180
CERTIFICATE_ISSUER: letsencrypt-prod
ENVIRONMENT: ${{ github.ref == 'refs/heads/master' && 'production' || 'staging' }}
ENVIRONMENT_RUNTIME_VAR_FILE: ${{ github.ref == 'refs/heads/master' && '.env.live' || '.env.staging' }}
jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
concurrency:
group: ${{ github.repository }}
cancel-in-progress: false
steps:
- uses: actions/checkout@v4

- name: Set Environmental Variables
id: set-variables
shell: pwsh
run: |
echo "CERTIFICATE_ORGANIZATION=${{ vars.CERTIFICATE_ORGANIZATION }}" >> $env:GITHUB_ENV;
if ('${{ github.ref }}' -eq 'refs/heads/master') {
echo "AZURE_SUBSCRIPTION_ID=${{ secrets.LIVE_AZURE_SUBSCRIPTION_ID }}" >> $env:GITHUB_ENV;
echo "AZURE_ACR_HOST=${{ secrets.LIVE_AZURE_ACR_HOST }}" >> $env:GITHUB_ENV;
echo "AZURE_ACR_USERNAME=${{ secrets.LIVE_AZURE_ACR_USERNAME }}" >> $env:GITHUB_ENV;
echo "AZURE_ACR_PASSWORD=${{ secrets.LIVE_AZURE_ACR_PASSWORD }}" >> $env:GITHUB_ENV;
echo "KUBERNETES_CLUSTER=${{ vars.PRODUCTION_KUBERNETES_CLUSTER }}" >> $env:GITHUB_ENV;
echo "CERTIFICATE_HOST=${{ vars.HOST_WEB_SUBDOMAIN }}.${{ vars.PRODUCTION_HOST }}" >> $env:GITHUB_ENV;
echo "API_URL=${{ vars.HOST_API_SUBDOMAIN }}.${{ vars.PRODUCTION_HOST }}" >> $env:GITHUB_ENV;
echo "NONCE_TOKEN=${{ vars.PRODUCTION_WEB_NONCE_TOKEN }}" >> $env:GITHUB_ENV;
}
elseif ('${{ github.ref }}' -eq 'refs/heads/staging') {
echo "AZURE_SUBSCRIPTION_ID=${{ secrets.STAGING_AZURE_SUBSCRIPTION_ID }}" >> $env:GITHUB_ENV;
echo "AZURE_ACR_HOST=${{ secrets.STAGING_AZURE_ACR_HOST }}" >> $env:GITHUB_ENV;
echo "AZURE_ACR_USERNAME=${{ secrets.STAGING_AZURE_ACR_USERNAME }}" >> $env:GITHUB_ENV;
echo "AZURE_ACR_PASSWORD=${{ secrets.STAGING_AZURE_ACR_PASSWORD }}" >> $env:GITHUB_ENV;
echo "KUBERNETES_CLUSTER=${{ vars.STAGING_KUBERNETES_CLUSTER }}" >> $env:GITHUB_ENV;
echo "CERTIFICATE_HOST=${{ vars.HOST_WEB_SUBDOMAIN }}.${{ vars.STAGING_HOST }}" >> $env:GITHUB_ENV;
echo "API_URL=${{ vars.HOST_API_SUBDOMAIN }}.${{ vars.STAGING_HOST }}" >> $env:GITHUB_ENV;
echo "NONCE_TOKEN=${{ vars.STAGING_WEB_NONCE_TOKEN }}" >> $env:GITHUB_ENV;
}
- name: Build and Deploy
shell: pwsh
run: |
sudo az login --service-principal -u "${{ secrets.AZURE_CLIENT_ID }}" -p "${{ secrets.AZURE_CLIENT_SECRET }}" --tenant "${{ secrets.AZURE_TENANT_ID }}" -o none;
sudo az account set -s $env:AZURE_SUBSCRIPTION_ID -o none;
sudo az aks get-credentials -g "${{ vars.AZURE_KUBERNETES_RESOURCE_GROUP }}" -n $env:KUBERNETES_CLUSTER --overwrite -o none;
Add-Content -Path $env:ENVIRONMENT_RUNTIME_VAR_FILE -Value `n;
Add-Content -Path $env:ENVIRONMENT_RUNTIME_VAR_FILE -Value NEXT_PUBLIC_VERSION=$env:VERSION;
Add-Content -Path $env:ENVIRONMENT_RUNTIME_VAR_FILE -Value NEXT_PUBLIC_API_URL=$env:API_URL;
Add-Content -Path $env:ENVIRONMENT_RUNTIME_VAR_FILE -Value NEXT_PUBLIC_NONCE_TOKEN=$env:NONCE_TOKEN;
sudo docker build `
-t $env:AZURE_ACR_HOST"/"$env:IMAGE_NAME":latest" `
-t $env:AZURE_ACR_HOST"/"$env:IMAGE_NAME":"$env:VERSION `
--build-arg ENVIRONMENT=$env:ENVIRONMENT `
--build-arg NODE_JS_VERSION=$env:NODE_JS_VERSION `
./;
if ($LastExitCode -ne 0)
{
throw "error";
};
sudo docker login -u="$env:AZURE_ACR_USERNAME" -p="$env:AZURE_ACR_PASSWORD" $env:AZURE_ACR_HOST;
sudo docker push $env:AZURE_ACR_HOST"/"$env:IMAGE_NAME":latest";
sudo docker push $env:AZURE_ACR_HOST"/"$env:IMAGE_NAME":"$env:VERSION;
if ($LastExitCode -ne 0)
{
throw "error";
};
Get-Content .kubernetes/certificate.yaml | foreach { [Environment]::ExpandEnvironmentVariables($_) } | Set-Content .kubernetes/certificate.tmp.yaml;
sudo kubectl apply -f .kubernetes/certificate.tmp.yaml;
if ($LastExitCode -ne 0)
{
throw "error";
};
Get-Content .kubernetes/service.yaml | foreach { [Environment]::ExpandEnvironmentVariables($_) } | Set-Content .kubernetes/service.tmp.yaml;
sudo kubectl apply -f .kubernetes/service.tmp.yaml;
if ($LastExitCode -ne 0)
{
throw "error";
};
Get-Content .kubernetes/configmap.yaml | foreach { [Environment]::ExpandEnvironmentVariables($_) } | Set-Content .kubernetes/configmap.tmp.yaml;
sudo kubectl apply -f .kubernetes/configmap.tmp.yaml;
if ($LastExitCode -ne 0)
{
throw "error";
};
Get-Content .kubernetes/deployment.yaml | foreach { [Environment]::ExpandEnvironmentVariables($_) } | Set-Content .kubernetes/deployment.tmp.yaml;
sudo kubectl apply -f .kubernetes/deployment.tmp.yaml;
if ($LastExitCode -ne 0)
{
throw "error";
};
Get-Content .kubernetes/autoscaler.yaml | foreach { [Environment]::ExpandEnvironmentVariables($_) } | Set-Content .kubernetes/autoscaler.tmp.yaml;
sudo kubectl apply -f .kubernetes/autoscaler.tmp.yaml;
if ($LastExitCode -ne 0)
{
throw "error";
};
Get-Content .kubernetes/ingress.yaml | foreach { [Environment]::ExpandEnvironmentVariables($_) } | Set-Content .kubernetes/ingress.tmp.yaml;
sudo kubectl apply -f .kubernetes/ingress.tmp.yaml;
if ($LastExitCode -ne 0)
{
throw "error";
};
- name: Slack Notification
if: always()
uses: act10ns/slack@v2
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
config: .github/config/slack.yml
status: ${{ job.status }}
channel: ${{ vars.SLACK_CHANNEL }}
37 changes: 37 additions & 0 deletions Web/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
.env
25 changes: 25 additions & 0 deletions Web/.kubernetes/autoscaler.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: %SERVICE_NAME%-hpa
namespace: %KUBERNETES_NAMESPACE%
spec:
minReplicas: %KUBERNETES_REPLICA_COUNT%
maxReplicas: %KUBERNETES_REPLICA_COUNT_MAX%
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: %SERVICE_NAME%
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: %KUBERNETES_CPU_SCALING%
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: %KUBERNETES_MEMORY_SCALING%
19 changes: 19 additions & 0 deletions Web/.kubernetes/certificate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: %SERVICE_NAME%-nginx-tls
namespace: %KUBERNETES_NAMESPACE%
spec:
secretName: %CERTIFICATE_HOST%-tls
duration: 2160h
renewBefore: 720h
subject:
organizations:
- %CERTIFICATE_ORGANIZATION%
dnsNames:
- %CERTIFICATE_HOST%
privateKey:
rotationPolicy: Always
issuerRef:
name: %CERTIFICATE_ISSUER%
kind: ClusterIssuer
7 changes: 7 additions & 0 deletions Web/.kubernetes/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: %SERVICE_NAME%-config
namespace: %KUBERNETES_NAMESPACE%
data:
App__Version: %VERSION%
82 changes: 82 additions & 0 deletions Web/.kubernetes/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: %SERVICE_NAME%
namespace: %KUBERNETES_NAMESPACE%
labels:
app: %SERVICE_NAME%
spec:
replicas: %KUBERNETES_REPLICA_COUNT%
revisionHistoryLimit: %KUBERNETES_REPLICA_HISTORY_COUNT%
selector:
matchLabels:
app: %SERVICE_NAME%
template:
metadata:
labels:
app: %SERVICE_NAME%
spec:
automountServiceAccountToken: false
securityContext:
runAsUser: 1000
runAsGroup: 2000
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: %SERVICE_NAME%
automountServiceAccountToken: false
containers:
- name: %SERVICE_NAME%
image: %AZURE_ACR_HOST%/%IMAGE_NAME%:%VERSION%
ports:
- containerPort: 8080
- containerPort: 4443
imagePullPolicy: Always
envFrom:
- configMapRef:
name: %SERVICE_NAME%-config
resources:
requests:
memory: %KUBERNETES_MEMORY_REQUEST%
cpu: %KUBERNETES_CPU_REQUEST%
limits:
memory: %KUBERNETES_MEMORY_LIMIT%
cpu: %KUBERNETES_CPU_LIMIT%
securityContext:
privileged: false
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 2000
capabilities:
drop:
- ALL
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
periodSeconds: 20
initialDelaySeconds: 25
readinessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
periodSeconds: 5
initialDelaySeconds: 20
volumeMounts:
- name: tmp
mountPath: /tmp
- name: npm-logs
mountPath: /home/node/.npm/_logs
volumes:
- name: tmp
emptyDir: {}
- name: npm-logs
emptyDir: {}

Loading

0 comments on commit 3fc022c

Please sign in to comment.