Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9050cf3
chor: Moved documentation files to Documentation directory
gustav-mb Apr 18, 2023
f137e1d
feat: Implemented initial Swarm script
gustav-mb Apr 18, 2023
6e6d1f0
chor: Changed back to old fingerprint
gustav-mb Apr 18, 2023
9882903
feat: Setup swarm
gustav-mb Apr 25, 2023
1537363
Merge branch 'main' into feat-swarm
gustav-mb Apr 25, 2023
25f60db
feat: Added group fingerprints
gustav-mb Apr 25, 2023
817e03c
chor: Updated ip address
gustav-mb Apr 25, 2023
9faada3
chor: Enabled manual dispatch
gustav-mb Apr 25, 2023
fb4f833
feat: Aded swarm deploy
gustav-mb Apr 25, 2023
bf49185
fix: Removed network name
gustav-mb Apr 25, 2023
2858da8
fix: Wrong spelling of network name
gustav-mb Apr 25, 2023
5995427
fix?
gustav-mb Apr 25, 2023
3e12b73
fix
gustav-mb Apr 25, 2023
4833e13
fix: Added creation of overlay network
gustav-mb Apr 25, 2023
0626ff6
chor: Changed server to development mode
gustav-mb Apr 25, 2023
4118a67
chor: Only copies production docker-compose
gustav-mb Apr 25, 2023
8b68ad2
chor: Added placement policy
gustav-mb Apr 25, 2023
f77378b
1
gustav-mb Apr 25, 2023
f1cdb09
chor: Removed placement
gustav-mb Apr 25, 2023
b1a58f7
chor: Removed container_name as it is not supported
gustav-mb Apr 25, 2023
79d138b
test backend
gustav-mb Apr 25, 2023
873f295
fix: Removed dependency for backend
gustav-mb Apr 25, 2023
5229755
chor: test
gustav-mb Apr 25, 2023
13ee6ae
chor: removed network creation
gustav-mb Apr 25, 2023
77a7c30
chor: Added new secret connection string
gustav-mb Apr 25, 2023
dcdb511
chor: Added 3 replicas
gustav-mb Apr 25, 2023
bc09fcf
up
gustav-mb Apr 25, 2023
3af3b9c
Merge branch 'main' into feat-swarm
simonskodt May 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/swarm-deployment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Swarm Deployment

on:
pull_request:
branches:
- main
workflow_dispatch:

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Copy docker-compose production file to Swarm Manager
uses: burnett01/[email protected]
with:
switches: -avz --delete --include="docker-compose.prod.yml" --exclude="*"
path: .
remote_path: ./itu-minitwit/
remote_host: ${{ secrets.SSH_HOST_SWARM }}
remote_user: ${{ secrets.SSH_USER }}
remote_key: ${{ secrets.SSH_PRIVATE_KEY }}

- name: Deploy MiniTwit
uses: fifsky/ssh-action@master
with:
host: ${{ secrets.SSH_HOST_SWARM }}
user: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
command: |
export DB_CONNECTION_STRING=${{ secrets.DB_CONNECTIONSTRING_SWARM }}
export DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }}
cd ./itu-minitwit
docker pull ${{ secrets.DOCKER_USERNAME }}/itu-minitwit-server:latest
docker pull ${{ secrets.DOCKER_USERNAME }}/itu-minitwit-web:latest
docker stack deploy -c docker-compose.prod.yml minitwit
15 changes: 6 additions & 9 deletions MiniTwit.Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,13 @@
app.SeedDatabase(app.Environment.IsDevelopment());

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
app.UseSwagger();
app.UseSwaggerUI(options =>
{
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "MiniTwit API");
options.DocumentTitle = "MiniTwit API - Swagger";
options.DisplayRequestDuration();
});
}
options.SwaggerEndpoint("/swagger/v1/swagger.json", "MiniTwit API");
options.DocumentTitle = "MiniTwit API - Swagger";
options.DisplayRequestDuration();
});

// Cross-origin Request Blocked
app.UseCors(x => x
Expand Down
3 changes: 3 additions & 0 deletions MiniTwit.Server/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"loki": {
"Uri": "http://loki:3100"
}
}
2 changes: 1 addition & 1 deletion MiniTwit.Server/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"TagLength": 128
},
"loki": {
"Uri": "http://loki:3100"
"Uri": "http://164.92.167.188:3100"
},
"Logging": {
"LogLevel": {
Expand Down
20 changes: 20 additions & 0 deletions Monitoring/prometheus.prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
global:
scrape_interval: 15s
evaluation_interval: 15s

external_labels:
monitor: 'codelab-monitor'

rule_files:
- 'prometheus.rules.yml'

scrape_configs:
- job_name: 'prometheus'
scrape_interval: 5s
static_configs:
- targets: ['prometheus:9090']

- job_name: 'itu-minitwit-app'
scrape_interval: 5s
static_configs:
- targets: ['128.199.3.151:80']
18 changes: 16 additions & 2 deletions docker-compose.monitoring.yml → docker-compose.main.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,27 @@ version: '3.4'
networks:
main:
name: itu-minitwit-network
external: true # Join MiniTwit network
driver: bridge

services:
mongodb:
image: mongo:latest
command: [--auth]
environment:
MONGO_INITDB_ROOT_USERNAME: radiator
MONGO_INITDB_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- mongodb_data_container:/data/db
ports:
- '27018:27017'
networks:
- main

prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./Monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
- ./Monitoring/prometheus.prod.yml:/etc/prometheus/prometheus.yml
- prometheus_storage:/prometheus
ports:
- "9090:9090"
Expand Down Expand Up @@ -56,3 +69,4 @@ volumes:
grafana_storage:
prometheus_storage:
loki_storage:
mongodb_data_container:
32 changes: 10 additions & 22 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -1,46 +1,34 @@
version: '3.4'

networks:
main:
name: itu-minitwit-network
driver: bridge
main:
driver: "overlay"

services:
mongodb:
image: mongo:latest
command: [--auth]
environment:
MONGO_INITDB_ROOT_USERNAME: radiator
MONGO_INITDB_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- mongodb_data_container:/data/db
ports:
- '27018:27017'
networks:
- main

itu-minitwit-server:
image: ${DOCKER_USERNAME}/itu-minitwit-server:latest
container_name: minitwit
environment:
ASPNETCORE_ENVIRONMENT: Development
ASPNETCORE_URLS: http://+:80
ConnectionStrings__MiniTwit: ${DB_CONNECTION_STRING}
deploy:
replicas: 3
update_config:
delay: 10s
ports:
- '80:80'
networks:
- main
depends_on:
- mongodb

itu-minitwit-web:
image: ${DOCKER_USERNAME}/itu-minitwit-web:latest
deploy:
replicas: 3
update_config:
delay: 10s
ports:
- '3000:3000'
networks:
- main
depends_on:
- itu-minitwit-server

volumes:
mongodb_data_container:
148 changes: 148 additions & 0 deletions swarm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/bin/bash

# Colors
red='\033[0;31m'
green='\033[0;32m'
clear='\033[0m'

function println {
printf "%b%b\n%b" "$2" "$1" "$clear"
}

if [ "$DIGITAL_OCEAN_TOKEN" == "" ]; then
println "'DIGITAL_OCEAN_TOKEN' environment variable is not set!" "$red"
exit
else
# Digital Ocean
export BEARER_AUTH_TOKEN="Authorization: Bearer $DIGITAL_OCEAN_TOKEN"
export JSON_CONTENT="Content-Type: application/json"
fi

function get_ip {
for (( ; ; ))
do
IP=$(curl -s GET "$DROPLETS_API"\
-H "$BEARER_AUTH_TOKEN" -H "$JSON_CONTENT"\
| jq -r "$JQFILTER")
sleep 5
if [ "$IP" != "" ]; then
echo "$IP"
break
fi
done
}

function createDockerSwarmClusterNode {
export DIGITALOCEAN_PRIVATE_NETWORKING=true
export DROPLETS_API="https://api.digitalocean.com/v2/droplets"

CONFIG='{"name":"Swarm-Manager","tags":["demo"],
"size":"s-1vcpu-1gb", "image":"docker-20-04",
"ssh_keys":["35:27:02:78:dc:a4:80:b6:90:77:9d:19:f2:46:f4:13", "6b:53:ee:b5:06:24:9a:63:96:c4:04:40:db:10:db:2a", "fd:df:2a:4b:4e:06:ce:a7:97:11:e1:88:23:6c:6d:7b", "81:33:1f:de:81:9b:5d:bf:0e:92:41:a7:53:96:52:ba"]}'

println "Creating Droplet..." "$green"
SWARM_MANAGER_ID=$(curl -X POST $DROPLETS_API -d "$CONFIG"\
-H "$BEARER_AUTH_TOKEN" -H "$JSON_CONTENT"\
| jq -r .droplet.id ) && sleep 5 && echo "$SWARM_MANAGER_ID"

export JQFILTER='.droplets | .[] | select (.name == "Swarm-Manager") | .networks.v4 | .[]| select (.type == "public") | .ip_address'

SWARM_MANAGER_IP=$(get_ip)
echo "Swarm Manager IP: $SWARM_MANAGER_IP"
println "Done." "$green"
}

function createWorkerNodes {
println "Creating worker1 Droplet..." "$green"
WORKER1_ID=$(curl -X POST $DROPLETS_API\
-d'{"name":"worker1","tags":["demo"],"region":"fra1",
"size":"s-1vcpu-1gb","image":"docker-20-04",
"ssh_keys":["35:27:02:78:dc:a4:80:b6:90:77:9d:19:f2:46:f4:13", "6b:53:ee:b5:06:24:9a:63:96:c4:04:40:db:10:db:2a", "fd:df:2a:4b:4e:06:ce:a7:97:11:e1:88:23:6c:6d:7b", "81:33:1f:de:81:9b:5d:bf:0e:92:41:a7:53:96:52:ba"]}'\
-H "$BEARER_AUTH_TOKEN" -H "$JSON_CONTENT" | jq -r .droplet.id ) && sleep 3 && echo "$WORKER1_ID"

export JQFILTER='.droplets | .[] | select (.name == "worker1") | .networks.v4 | .[]| select (.type == "public") | .ip_address'

WORKER1_IP=$(get_ip)
echo "Worker1 IP: $WORKER1_IP"
println "Done." "$green"

println "Creating worker2 Droplet..." "$green"
WORKER2_ID=$(curl -X POST $DROPLETS_API\
-d'{"name":"worker2","tags":["demo"],"region":"fra1",
"size":"s-1vcpu-1gb","image":"docker-20-04",
"ssh_keys":["35:27:02:78:dc:a4:80:b6:90:77:9d:19:f2:46:f4:13", "6b:53:ee:b5:06:24:9a:63:96:c4:04:40:db:10:db:2a", "fd:df:2a:4b:4e:06:ce:a7:97:11:e1:88:23:6c:6d:7b", "81:33:1f:de:81:9b:5d:bf:0e:92:41:a7:53:96:52:ba"]}'\
-H "$BEARER_AUTH_TOKEN" -H "$JSON_CONTENT"\
| jq -r .droplet.id )\
&& sleep 3 && echo "$WORKER2_ID"

export JQFILTER='.droplets | .[] | select (.name == "worker2") | .networks.v4 | .[]| select (.type == "public") | .ip_address'

WORKER2_IP=$(get_ip)
echo "Worker2 IP: $WORKER2_IP"
println "Done." "$green"
}

function makeSwarmManagerClusterManager {
println "Open the ports that Docker needs..." "$green"
ssh root@"$SWARM_MANAGER_IP" -i ~/.ssh/"$SSH_KEY" "ufw allow 22/tcp && ufw allow 2376/tcp &&\
ufw allow 2377/tcp && ufw allow 7946/tcp && ufw allow 7946/udp &&\
ufw allow 4789/udp && ufw reload && ufw --force enable &&\
systemctl restart docker"
println "Done." "$green"

println "Initialize the swarm..." "$green"
ssh root@"$SWARM_MANAGER_IP" -i ~/.ssh/"$SSH_KEY" "docker swarm init --advertise-addr $SWARM_MANAGER_IP"
ssh root@"$SWARM_MANAGER_IP" -i ~/.ssh/"$SSH_KEY" "docker swarm join-token worker -q"
WORKER_TOKEN=`ssh root@"$SWARM_MANAGER_IP" -i ~/.ssh/"$SSH_KEY" "docker swarm join-token worker -q"`
println "Done." "$green"

println "Build a command that we can run on node-1 and node-2 to join the swarm...." "$green"
REMOTE_JOIN_CMD="docker swarm join --token $WORKER_TOKEN $SWARM_MANAGER_IP:2377"
ssh root@"$WORKER1_IP" -i ~/.ssh/"$SSH_KEY" "$REMOTE_JOIN_CMD"
ssh root@"$WORKER2_IP" -i ~/.ssh/"$SSH_KEY" "$REMOTE_JOIN_CMD"
println "Done." "$green"
}

function getClusterManagerState {
println "Seeing the state of the cluster on the manager..." "$green"
ssh root@"$SWARM_MANAGER_IP" -i ~/.ssh/"$SSH_KEY" "docker node ls"
println "Done." "$green"
}

function startService {
println "Running a service on our cluster..." "$green"
ssh root@"$SWARM_MANAGER_IP" -i ~/.ssh/"$SSH_KEY" "docker service create -p 8080:8080 --name appserver stifstof/crashserver"
println "Done." "$green"
}

function removeDroplets {
println "Removing swarm droplets..." "$red"
curl -X DELETE\
-H "$BEARER_AUTH_TOKEN" -H "$JSON_CONTENT"\
"https://api.digitalocean.com/v2/droplets?tag_name=demo"
println "Done." "$red"
}

function print_help {
println "--- RUN HELP ---" "$green"
println "Available Commands:"
println ">> -i <SSH key> - The private SSH key to use"
println ">> clean - Remove remote Swarm Cluster Droplets"
println ">> -h - Print this page"
println "----------------" "$green"
}

if [ "$1" == "-i" ] && [ "$2" != "" ]; then
export SSH_KEY="$2"
createDockerSwarmClusterNode
createWorkerNodes
makeSwarmManagerClusterManager
getClusterManagerState
elif [ "$1" == "clean" ]; then
removeDroplets
elif [ "$1" == "-h" ]; then
print_help
else
println "Error: Unknown command" "$red"
println "For a list of available commands type './swarm.sh -h'" "$red"
fi