Files
tankwar_proj/deploy/k8s/scripts/run-deploy.sh
2026-05-02 13:50:52 +08:00

166 lines
6.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# =============================================================================
# Tank War Server — one-shot K8s deploy
#
# Mirrors the style of WarmCheck's run-deploy.sh:
# 1) sync source to master
# 2) build docker image on master
# 3) distribute image tarball to all worker nodes and `ctr` import
# 4) apply K8s manifests and restart the deployment
# =============================================================================
set -euo pipefail
# ---------- Configurable ------------------------------------------------------
# Host that the LOCAL developer machine can reach (uses your ssh_config alias).
MASTER_HOST="${MASTER_HOST:-host_172.16.16.16}"
# Intranet IPs that the MASTER uses to reach workers (no alias on the CVMs).
WORKER_INTRANET_IPS=(
"172.16.16.17"
"172.16.16.8"
)
NAMESPACE="tankwar"
IMAGE_NAME="tankwar-server"
IMAGE_TAG="${IMAGE_TAG:-latest}"
REMOTE_WORKDIR="/root/tankwar"
SSH_USER="root"
SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=10"
# ---------- Paths -------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
SERVER_DIR="${PROJECT_ROOT}/server"
K8S_DIR="${PROJECT_ROOT}/deploy/k8s"
# ---------- Helpers -----------------------------------------------------------
log() { printf "\033[1;36m[deploy]\033[0m %s\n" "$*"; }
ok() { printf "\033[1;32m[ ok ]\033[0m %s\n" "$*"; }
warn() { printf "\033[1;33m[warn]\033[0m %s\n" "$*"; }
die() { printf "\033[1;31m[fail]\033[0m %s\n" "$*" >&2; exit 1; }
ssh_master() { ssh ${SSH_OPTS} "${SSH_USER}@${MASTER_HOST}" "$@"; }
ssh_host() { local h="$1"; shift; ssh ${SSH_OPTS} "${SSH_USER}@${h}" "$@"; }
# =============================================================================
# Step 1 — sync server source code & k8s manifests to master
# =============================================================================
step_sync() {
log "1/5 Syncing source to master (${MASTER_HOST}) ..."
ssh_master "mkdir -p ${REMOTE_WORKDIR}/server ${REMOTE_WORKDIR}/deploy/k8s"
rsync -az --delete \
--exclude 'node_modules' \
--exclude '.git' \
--exclude '.DS_Store' \
-e "ssh ${SSH_OPTS}" \
"${SERVER_DIR}/" \
"${SSH_USER}@${MASTER_HOST}:${REMOTE_WORKDIR}/server/"
rsync -az --delete \
-e "ssh ${SSH_OPTS}" \
"${K8S_DIR}/" \
"${SSH_USER}@${MASTER_HOST}:${REMOTE_WORKDIR}/deploy/k8s/"
ok "source synced"
}
# =============================================================================
# Step 2 — build docker image on master
# =============================================================================
step_build() {
log "2/5 Building image ${IMAGE_NAME}:${IMAGE_TAG} on master ..."
ssh_master "cd ${REMOTE_WORKDIR}/server && \
docker build --pull -t ${IMAGE_NAME}:${IMAGE_TAG} -t ${IMAGE_NAME}:latest ."
ok "image built"
}
# =============================================================================
# Step 3 — distribute image to every worker via containerd (ctr import)
#
# The cluster uses containerd directly (not docker-shim). Each node must
# have the image in the "k8s.io" namespace to be usable by kubelet.
# =============================================================================
step_distribute() {
log "3/5 Distributing image to workers ..."
# Export once on master
local remote_tar="/tmp/${IMAGE_NAME}-${IMAGE_TAG}.tar"
ssh_master "docker save ${IMAGE_NAME}:${IMAGE_TAG} -o ${remote_tar} && ls -lh ${remote_tar}"
# Import on master's containerd (k8s.io ns) so the scheduler can use it locally too
ssh_master "ctr -n k8s.io images import ${remote_tar} && \
ctr -n k8s.io images tag --force docker.io/library/${IMAGE_NAME}:${IMAGE_TAG} \
docker.io/library/${IMAGE_NAME}:latest"
ok "master imported"
# Fan-out to workers — executed FROM the master using intranet IPs.
for ip in "${WORKER_INTRANET_IPS[@]}"; do
log " -> ${ip}"
ssh_master "scp ${SSH_OPTS} ${remote_tar} ${SSH_USER}@${ip}:${remote_tar} && \
ssh ${SSH_OPTS} ${SSH_USER}@${ip} 'ctr -n k8s.io images import ${remote_tar} && \
ctr -n k8s.io images tag --force docker.io/library/${IMAGE_NAME}:${IMAGE_TAG} \
docker.io/library/${IMAGE_NAME}:latest && \
rm -f ${remote_tar}'"
ok " ${ip} imported"
done
ssh_master "rm -f ${remote_tar}"
ok "distribution done"
}
# =============================================================================
# Step 4 — apply manifests & roll the deployment
# =============================================================================
step_apply() {
log "4/5 Applying K8s manifests ..."
ssh_master "kubectl apply -f ${REMOTE_WORKDIR}/deploy/k8s/namespace.yaml"
ssh_master "kubectl apply -f ${REMOTE_WORKDIR}/deploy/k8s/service.yaml"
ssh_master "kubectl apply -f ${REMOTE_WORKDIR}/deploy/k8s/deployment.yaml"
# Force a new rollout so we pick up the newly-imported image even
# when the tag stays :latest.
ssh_master "kubectl -n ${NAMESPACE} set image deploy/tankwar-server \
tankwar-server=${IMAGE_NAME}:${IMAGE_TAG} --record=false || true"
log " waiting for rollout ..."
ssh_master "kubectl -n ${NAMESPACE} rollout status deploy/tankwar-server --timeout=180s"
ok "deployment is live"
}
# =============================================================================
# Step 5 — sanity check
# =============================================================================
step_verify() {
log "5/5 Verifying ..."
ssh_master "kubectl -n ${NAMESPACE} get pods,svc -o wide"
echo
ssh_master "kubectl -n ${NAMESPACE} logs deploy/tankwar-server --tail=20 || true"
echo
ok "all done. NodePort: 30081"
cat <<EOF
------------------------------------------------------------
Public endpoints (after DNS on www.igeek.site takes effect):
wss://www.igeek.site:30081/ (via NodePort on any of the 3 CVMs)
Direct CVM access for smoke test:
wscat -c ws://43.139.80.61:30081/
wscat -c ws://43.138.255.42:30081/
wscat -c ws://159.75.104.221:30081/
Remember to allow TCP/30081 in the CVM security group.
------------------------------------------------------------
EOF
}
main() {
log "Tank War Server deploy — tag=${IMAGE_TAG}"
step_sync
step_build
step_distribute
step_apply
step_verify
}
main "$@"