Skip to content
This repository was archived by the owner on Jan 11, 2026. It is now read-only.

Commit e0cfa65

Browse files
committed
SNA
1 parent 62a83ca commit e0cfa65

File tree

22 files changed

+1215
-54
lines changed

22 files changed

+1215
-54
lines changed

.github/workflows/deploy.yml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
name: Deploy to Server
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
8+
jobs:
9+
build-and-deploy:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Checkout repository
13+
uses: actions/checkout@v3
14+
15+
- name: Set up SSH
16+
uses: webfactory/ssh-agent@v0.5.4
17+
with:
18+
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
19+
20+
- name: Check if docker-compose-generator.py has changed
21+
id: check_changes
22+
run: |
23+
if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep -q "docker-compose-generator.py"; then
24+
if ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} '[ -f /opt/sharder/docker-compose.yml ]'; then
25+
echo "Error: docker-compose-generator.py has changed and docker-compose.yml exists on target"
26+
exit 1
27+
fi
28+
fi
29+
30+
- name: Prepare remote directory
31+
run: |
32+
ssh -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
33+
'mkdir -p /opt/sharder && touch /opt/sharder/.preserve'
34+
35+
- name: Sync files
36+
run: |
37+
rsync -avz --exclude '.git*' --exclude 'docker-compose.yml' . ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/opt/sharder
38+
39+
- name: Run live test on temporary instance
40+
run: |
41+
ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'EOF'
42+
set -euo pipefail
43+
44+
TMP_DIR=/tmp/sharder-$(openssl rand -hex 4)
45+
cp -r /opt/sharder "$TMP_DIR"
46+
47+
cd "$TMP_DIR"
48+
rm docker-compose.yml || true
49+
python3 docker-compose-generator.py --chunks-per-file 2 --replicas 3 --dev-shards 3
50+
docker compose up -d --build --remove-orphans
51+
52+
while ! docker compose ps | grep -q "Up"; do
53+
echo "Waiting for containers to be up..."
54+
sleep 1
55+
done
56+
57+
echo "Waiting for nginx to become available..."
58+
for i in {1..20}; do
59+
if curl --silent --unix-socket "$TMP_DIR/socks/nginx.sock" http://localhost; then
60+
echo "✅ nginx is up and running"
61+
break
62+
else
63+
echo "⏳ Attempt $i/20: nginx not responding yet..."
64+
sleep 1
65+
fi
66+
done || (echo "❌ nginx failed to start after 20 attempts" && exit 1)
67+
68+
echo "Running external tests..."
69+
TEST_EXIT=0
70+
curl -sS https://bootstrap.pypa.io/get-pip.py | python3
71+
python3 -m pip install requests-unixsocket
72+
python3 tests.py || TEST_EXIT=$?
73+
74+
if [ "$TEST_EXIT" -ne 0 ]; then
75+
echo "❌ Tests failed. Check logs for details."
76+
docker compose logs
77+
fi
78+
79+
echo "Cleaning up containers and temporary files..."
80+
docker compose down --remove-orphans || true
81+
rm -rf "$TMP_DIR" || true
82+
83+
if [ "$TEST_EXIT" -ne 0 ]; then
84+
echo "❌ Tests failed. Aborting."
85+
docker compose logs
86+
exit 1
87+
fi
88+
89+
echo "✅ Tests passed."
90+
EOF
91+
92+
- name: Deploy with Docker Compose
93+
run: |
94+
ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'EOF'
95+
cd /opt/sharder
96+
docker compose pull --ignore-pull-failures
97+
docker compose up -d --build --remove-orphans
98+
EOF

default.conf

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ server {
1818
}
1919

2020
location /api {
21-
proxy_pass http://sharder-server:8000;
21+
proxy_pass http://server:8000;
2222
proxy_set_header Host $host;
2323
proxy_set_header X-Real-IP $remote_addr;
2424
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@@ -31,3 +31,11 @@ server {
3131
proxy_busy_buffers_size 256k;
3232
}
3333
}
34+
35+
server {
36+
listen 9113;
37+
38+
location /nginx_status {
39+
stub_status on;
40+
}
41+
}

docker-compose-generator.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,6 @@
1616
help="Number of replicas. This is the number of copies of each chunk that will be stored on different shards.",
1717
default=2,
1818
)
19-
parser.add_argument(
20-
"--public-port",
21-
type=int,
22-
help="Public port for the frontend service. This is the port that will be exposed to the outside world.",
23-
default=80,
24-
)
2519
parser.add_argument(
2620
"--dev-shards",
2721
type=int,
@@ -32,18 +26,18 @@
3226

3327
PG_PASSWORD = os.urandom(16).hex()
3428
CONNECTION_SECRET = os.urandom(16)
29+
while "/" in base64.b64encode(CONNECTION_SECRET).decode().strip("="):
30+
CONNECTION_SECRET = os.urandom(16)
3531

3632
base = {
3733
"services": {
3834
"frontend": {
3935
"build": {"context": "./frontend"},
40-
"container_name": "frontend",
4136
"networks": ["shard_net"],
4237
"restart": "unless-stopped",
4338
},
4439
"server": {
4540
"build": {"context": "./server"},
46-
"container_name": "sharder-server",
4741
"depends_on": ["postgres"],
4842
"networks": ["shard_net"],
4943
"restart": "unless-stopped",
@@ -54,15 +48,21 @@
5448
"CONNECTION_SECRET": CONNECTION_SECRET.hex(),
5549
"DB_URL": f"postgresql://shard:{PG_PASSWORD}@postgres/shard",
5650
},
51+
"volumes": ["./prometheus/file_sd:/file_sd"],
5752
},
5853
"nginx": {
5954
"image": "nginx:latest",
60-
"ports": [f"{args.public_port}:80"],
6155
"depends_on": ["frontend", "server"],
6256
"networks": ["shard_net"],
6357
"restart": "unless-stopped",
6458
"volumes": ["./default.conf:/etc/nginx/conf.d/default.conf"],
6559
},
60+
"nginx-exporter": {
61+
"image": "nginx/nginx-prometheus-exporter:latest",
62+
"command": "--nginx.scrape-uri=http://nginx:9113/nginx_status --web.listen-address=:9113",
63+
"depends_on": ["nginx"],
64+
"networks": ["shard_net"],
65+
},
6666
"postgres": {
6767
"image": "postgres:latest",
6868
"networks": ["shard_net"],
@@ -74,26 +74,54 @@
7474
"POSTGRES_PASSWORD": PG_PASSWORD,
7575
},
7676
},
77+
"prometheus": {
78+
"image": "prom/prometheus:latest",
79+
"volumes": [
80+
"./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro",
81+
"./prometheus/file_sd:/etc/prometheus/file_sd",
82+
],
83+
"networks": ["shard_net"],
84+
},
85+
"grafana": {
86+
"image": "grafana/grafana:latest",
87+
"environment": {
88+
"GF_SECURITY_ADMIN_PASSWORD": os.urandom(16).hex(),
89+
"GF_INSTALL_PLUGINS": "grafana-piechart-panel,grafana-clock-panel",
90+
},
91+
"volumes": [
92+
"grafana-data:/var/lib/grafana",
93+
"./grafana/provisioning:/etc/grafana/provisioning:ro",
94+
],
95+
"depends_on": ["prometheus"],
96+
"networks": ["shard_net"],
97+
},
98+
"socket-proxy": {
99+
"image": "docker.io/alpine/socat",
100+
"volumes": ["./socks:/socks", "./socat-entrypoint.sh:/socat-entrypoint.sh"],
101+
"entrypoint": ["/bin/sh"],
102+
"command": "/socat-entrypoint.sh",
103+
"depends_on": ["grafana", "nginx", "prometheus"],
104+
"networks": ["shard_net"],
105+
},
77106
},
78107
"volumes": {
79108
"postgres-storage": {},
109+
"grafana-data": {},
80110
},
81111
"networks": {"shard_net": {}},
82112
}
83113

84114
for i in range(args.dev_shards):
115+
token = base64.b64encode(CONNECTION_SECRET).decode().strip("=")
85116
base["services"][f"shard-{i}"] = {
86117
"build": {"context": "./shard"},
87-
"container_name": f"shard-{i}",
88118
"networks": ["shard_net"],
89119
"restart": "unless-stopped",
90120
"depends_on": ["server"],
91-
"environment": {
92-
"SHARD_TOKEN": base64.b64encode(CONNECTION_SECRET).decode().strip("=")
93-
},
94121
"volumes": [
95122
f"shard-{i}-storage:/opt/shard/.data",
96123
],
124+
"command": f"sh -c 'export SHARD_PUBLIC_IP=$(hostname -i) && ./shard \"http://nginx/api/connect/{token}\" --dry'",
97125
}
98126
base["volumes"][f"shard-{i}-storage"] = {}
99127

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: 1
2+
providers:
3+
- name: 'Sharder dashboards'
4+
orgId: 1
5+
folder: ''
6+
type: file
7+
options:
8+
path: /etc/grafana/provisioning/dashboards/sharder

0 commit comments

Comments
 (0)