chore: add aslan deploy runner
This commit is contained in:
parent
0901496c7f
commit
e46681d4b7
301
.deploy/aslan-deploy/deploy-likei-services.sh
Executable file
301
.deploy/aslan-deploy/deploy-likei-services.sh
Executable file
@ -0,0 +1,301 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BASE_DIR="${BASE_DIR:-/opt/aslan-deploy}"
|
||||||
|
SRC_DIR="${SRC_DIR:-$BASE_DIR/source/likei-services}"
|
||||||
|
KUBECONFIG="${KUBECONFIG:-$BASE_DIR/kubeconfig}"
|
||||||
|
NAMESPACE="${NAMESPACE:-prod}"
|
||||||
|
MODE="${MODE:-preload}"
|
||||||
|
SKIP_BUILD="${SKIP_BUILD:-0}"
|
||||||
|
USE_GIT_SOURCE="${USE_GIT_SOURCE:-0}"
|
||||||
|
GIT_REMOTE_URL="${GIT_REMOTE_URL:-git@gitea.haiyihy.com:hy/aslan-server.git}"
|
||||||
|
GIT_REF="${GIT_REF:-atyou_prod}"
|
||||||
|
MAVEN_EXTRA_ARGS="${MAVEN_EXTRA_ARGS:-}"
|
||||||
|
BUILD_TS="${BUILD_TS:-$(date +%Y%m%dv%H%M%S)}"
|
||||||
|
BASE_IMAGE="tuokemi-con-registry.ap-southeast-1.cr.aliyuncs.com/public_mirror_images/eclipse-temurin:17-jdk-jammy"
|
||||||
|
FALLBACK_BASE_IMAGE="${FALLBACK_BASE_IMAGE:-eclipse-temurin:17-jdk-jammy}"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
deploy-likei-services.sh [--mode preload|push|build-only|status] [--skip-build] [other|external|console ...]
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
/opt/aslan-deploy/deploy-likei-services.sh status
|
||||||
|
/opt/aslan-deploy/deploy-likei-services.sh --mode preload other external console
|
||||||
|
USE_GIT_SOURCE=1 GIT_REF=atyou_prod /opt/aslan-deploy/deploy-likei-services.sh --mode preload other
|
||||||
|
MODE=push ALIYUN_USER=xxx ALIYUN_PASS=xxx /opt/aslan-deploy/deploy-likei-services.sh other
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- preload mode builds the image on this server, imports it into each TKE node's containerd, then updates the deployment.
|
||||||
|
- push mode follows the original Jenkins flow and requires registry credentials in ALIYUN_USER/ALIYUN_PASS.
|
||||||
|
- USE_GIT_SOURCE=1 clones or resets source from GIT_REMOTE_URL/GIT_REF before building.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '[%s] %s\n' "$(date '+%F %T')" "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
need_cmd() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || {
|
||||||
|
echo "missing command: $1" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_base_image() {
|
||||||
|
if docker image inspect "$BASE_IMAGE" >/dev/null 2>&1; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
log "base image not cached, pulling $FALLBACK_BASE_IMAGE"
|
||||||
|
docker pull "$FALLBACK_BASE_IMAGE"
|
||||||
|
docker tag "$FALLBACK_BASE_IMAGE" "$BASE_IMAGE"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_source_from_git() {
|
||||||
|
if [[ "$USE_GIT_SOURCE" != "1" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
need_cmd git
|
||||||
|
mkdir -p "$(dirname "$SRC_DIR")"
|
||||||
|
if [[ ! -d "$SRC_DIR/.git" ]]; then
|
||||||
|
rm -rf "$SRC_DIR"
|
||||||
|
log "git clone $GIT_REMOTE_URL ($GIT_REF) -> $SRC_DIR"
|
||||||
|
git clone --branch "$GIT_REF" "$GIT_REMOTE_URL" "$SRC_DIR"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "git reset source to origin/$GIT_REF from $GIT_REMOTE_URL"
|
||||||
|
git -C "$SRC_DIR" remote set-url origin "$GIT_REMOTE_URL"
|
||||||
|
git -C "$SRC_DIR" fetch origin "$GIT_REF"
|
||||||
|
git -C "$SRC_DIR" checkout "$GIT_REF"
|
||||||
|
git -C "$SRC_DIR" reset --hard "origin/$GIT_REF"
|
||||||
|
}
|
||||||
|
|
||||||
|
service_module() {
|
||||||
|
case "$1" in
|
||||||
|
other) echo "rc-service/rc-service-other/other-start" ;;
|
||||||
|
external) echo "rc-service/rc-service-external/external-start" ;;
|
||||||
|
console) echo "rc-service/rc-service-console/console-start" ;;
|
||||||
|
*) echo "unsupported service: $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
service_dir() {
|
||||||
|
case "$1" in
|
||||||
|
other) echo "rc-service/rc-service-other" ;;
|
||||||
|
external) echo "rc-service/rc-service-external" ;;
|
||||||
|
console) echo "rc-service/rc-service-console" ;;
|
||||||
|
*) echo "unsupported service: $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
image_repo() {
|
||||||
|
case "$1" in
|
||||||
|
other) echo "tuokemi-con-registry.ap-southeast-1.cr.aliyuncs.com/atyou-prod/other" ;;
|
||||||
|
external) echo "tuokemi-con-registry.ap-southeast-1.cr.aliyuncs.com/atyou-prod/external" ;;
|
||||||
|
console) echo "tuokemi-con-registry.ap-southeast-1.cr.aliyuncs.com/atyou-prod/console" ;;
|
||||||
|
*) echo "unsupported service: $1" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
build_service() {
|
||||||
|
local svc="$1"
|
||||||
|
local module
|
||||||
|
local dir
|
||||||
|
local repo
|
||||||
|
local tag
|
||||||
|
local image
|
||||||
|
module="$(service_module "$svc")"
|
||||||
|
dir="$(service_dir "$svc")"
|
||||||
|
repo="$(image_repo "$svc")"
|
||||||
|
tag="${svc}-${BUILD_TS}"
|
||||||
|
image="${repo}:${tag}"
|
||||||
|
|
||||||
|
cd "$SRC_DIR"
|
||||||
|
if [[ "$SKIP_BUILD" != "1" ]]; then
|
||||||
|
log "maven package $svc ($module)"
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
mvn clean package -pl "$module" -am -P prod -Dmaven.test.skip=true $MAVEN_EXTRA_ARGS
|
||||||
|
fi
|
||||||
|
|
||||||
|
ensure_base_image
|
||||||
|
log "docker build $image"
|
||||||
|
docker build \
|
||||||
|
--build-arg "SERVICE_VERSION=atyou-prod:${tag}" \
|
||||||
|
-f "$dir/Dockerfile" \
|
||||||
|
-t "$image" \
|
||||||
|
"$dir"
|
||||||
|
docker tag "$image" "${repo}:latest"
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
build-only)
|
||||||
|
log "build-only completed for $svc: $image"
|
||||||
|
;;
|
||||||
|
push)
|
||||||
|
push_image "$svc" "$image" "$repo"
|
||||||
|
rollout "$svc" "$image"
|
||||||
|
;;
|
||||||
|
preload)
|
||||||
|
preload_image_to_nodes "$svc" "$image"
|
||||||
|
rollout "$svc" "$image"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "unsupported MODE: $MODE" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
push_image() {
|
||||||
|
local svc="$1"
|
||||||
|
local image="$2"
|
||||||
|
local repo="$3"
|
||||||
|
if [[ -n "${ALIYUN_USER:-}" && -n "${ALIYUN_PASS:-}" ]]; then
|
||||||
|
log "docker login registry for $svc"
|
||||||
|
printf '%s' "$ALIYUN_PASS" | docker login --username "$ALIYUN_USER" --password-stdin tuokemi-con-registry.ap-southeast-1.cr.aliyuncs.com
|
||||||
|
fi
|
||||||
|
log "docker push $image"
|
||||||
|
docker push "$image"
|
||||||
|
docker push "${repo}:latest"
|
||||||
|
}
|
||||||
|
|
||||||
|
preload_image_to_nodes() {
|
||||||
|
local svc="$1"
|
||||||
|
local image="$2"
|
||||||
|
local safe_tag="${image//[^A-Za-z0-9_.-]/-}"
|
||||||
|
local tar_path="$BASE_DIR/artifacts/${safe_tag}.tar"
|
||||||
|
mkdir -p "$BASE_DIR/artifacts"
|
||||||
|
log "docker save $image -> $tar_path"
|
||||||
|
docker save "$image" -o "$tar_path"
|
||||||
|
|
||||||
|
mapfile -t nodes < <(kubectl --kubeconfig "$KUBECONFIG" get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')
|
||||||
|
if [[ "${#nodes[@]}" -eq 0 ]]; then
|
||||||
|
echo "no kubernetes nodes found" >&2
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
for node in "${nodes[@]}"; do
|
||||||
|
preload_image_to_node "$svc" "$image" "$tar_path" "$node"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
preload_image_to_node() {
|
||||||
|
local svc="$1"
|
||||||
|
local image="$2"
|
||||||
|
local tar_path="$3"
|
||||||
|
local node="$4"
|
||||||
|
local pod="image-preload-${svc}-${node//[^a-zA-Z0-9-]/-}-$(date +%s)"
|
||||||
|
local manifest
|
||||||
|
manifest="$(mktemp)"
|
||||||
|
cat >"$manifest" <<EOF
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: ${pod}
|
||||||
|
namespace: ${NAMESPACE}
|
||||||
|
spec:
|
||||||
|
nodeName: "${node}"
|
||||||
|
restartPolicy: Never
|
||||||
|
hostPID: true
|
||||||
|
tolerations:
|
||||||
|
- operator: Exists
|
||||||
|
containers:
|
||||||
|
- name: preload
|
||||||
|
image: docker:26.1.3-dind
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command: ["sh", "-c", "sleep 3600"]
|
||||||
|
securityContext:
|
||||||
|
privileged: true
|
||||||
|
volumeMounts:
|
||||||
|
- name: containerd
|
||||||
|
mountPath: /run/containerd/containerd.sock
|
||||||
|
volumes:
|
||||||
|
- name: containerd
|
||||||
|
hostPath:
|
||||||
|
path: /run/containerd/containerd.sock
|
||||||
|
type: Socket
|
||||||
|
EOF
|
||||||
|
log "create preload pod $pod on node $node"
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" apply -f "$manifest" >/dev/null
|
||||||
|
rm -f "$manifest"
|
||||||
|
if ! kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" wait --for=condition=Ready "pod/$pod" --timeout=180s >/dev/null; then
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" describe "pod/$pod" || true
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" delete pod "$pod" --ignore-not-found=true >/dev/null
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
log "copy image tar to $pod"
|
||||||
|
if ! kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" cp "$tar_path" "$pod:/tmp/image.tar" -c preload >/dev/null; then
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" delete pod "$pod" --ignore-not-found=true >/dev/null
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
log "import $image into node $node"
|
||||||
|
if ! kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" exec "$pod" -c preload -- \
|
||||||
|
ctr --address /run/containerd/containerd.sock -n k8s.io images import /tmp/image.tar >/dev/null; then
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" delete pod "$pod" --ignore-not-found=true >/dev/null
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" delete pod "$pod" --ignore-not-found=true >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
rollout() {
|
||||||
|
local svc="$1"
|
||||||
|
local image="$2"
|
||||||
|
log "set image deployment/$svc $svc=$image"
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" set image "deployment/$svc" "$svc=$image"
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" rollout status "deployment/$svc" --timeout=600s
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" get deploy "$svc" -o wide
|
||||||
|
}
|
||||||
|
|
||||||
|
status() {
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" -n "$NAMESPACE" get deploy other external console -o wide
|
||||||
|
kubectl --kubeconfig "$KUBECONFIG" get nodes -o wide
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--mode)
|
||||||
|
MODE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--skip-build)
|
||||||
|
SKIP_BUILD=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
need_cmd java
|
||||||
|
need_cmd mvn
|
||||||
|
need_cmd docker
|
||||||
|
need_cmd kubectl
|
||||||
|
[[ -f "$KUBECONFIG" ]] || { echo "missing kubeconfig: $KUBECONFIG" >&2; exit 2; }
|
||||||
|
|
||||||
|
if [[ "${1:-}" == "status" || "$MODE" == "status" ]]; then
|
||||||
|
status
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
update_source_from_git
|
||||||
|
|
||||||
|
local services=("$@")
|
||||||
|
if [[ "${#services[@]}" -eq 0 ]]; then
|
||||||
|
services=(other external console)
|
||||||
|
fi
|
||||||
|
|
||||||
|
for svc in "${services[@]}"; do
|
||||||
|
build_service "$svc"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
76
.deploy/aslan-deploy/sync-and-deploy.sh
Executable file
76
.deploy/aslan-deploy/sync-and-deploy.sh
Executable file
@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DEPLOY_HOST="${DEPLOY_HOST:-43.160.245.220}"
|
||||||
|
DEPLOY_USER="${DEPLOY_USER:-ubuntu}"
|
||||||
|
SSH_KEY="${SSH_KEY:-$HOME/.ssh/aslan-deploy-sg-ed25519}"
|
||||||
|
REMOTE_BASE="${REMOTE_BASE:-/opt/aslan-deploy}"
|
||||||
|
REMOTE_SRC="$REMOTE_BASE/source/likei-services"
|
||||||
|
LOCAL_M2_ROOT="${LOCAL_M2_ROOT:-$HOME/.m2/repository}"
|
||||||
|
REMOTE_M2_ROOT="${REMOTE_M2_ROOT:-/home/$DEPLOY_USER/.m2/repository}"
|
||||||
|
M2_CACHE_GROUPS="${M2_CACHE_GROUPS:-com/red/circle com/github/sud}"
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
.deploy/aslan-deploy/sync-and-deploy.sh [remote deploy args...]
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
.deploy/aslan-deploy/sync-and-deploy.sh status
|
||||||
|
.deploy/aslan-deploy/sync-and-deploy.sh --mode preload other
|
||||||
|
.deploy/aslan-deploy/sync-and-deploy.sh --mode preload other external console
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
DEPLOY_HOST default 43.160.245.220
|
||||||
|
DEPLOY_USER default ubuntu
|
||||||
|
SSH_KEY default ~/.ssh/aslan-deploy-sg-ed25519
|
||||||
|
|
||||||
|
Git source on deploy host:
|
||||||
|
ssh -i ~/.ssh/aslan-deploy-sg-ed25519 ubuntu@43.160.245.220 \
|
||||||
|
'USE_GIT_SOURCE=1 GIT_REF=atyou_prod /opt/aslan-deploy/deploy-likei-services.sh --mode preload other'
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
ssh_base=(ssh -i "$SSH_KEY" -o StrictHostKeyChecking=accept-new "$DEPLOY_USER@$DEPLOY_HOST")
|
||||||
|
rsync_ssh="ssh -i $SSH_KEY -o StrictHostKeyChecking=accept-new"
|
||||||
|
|
||||||
|
"${ssh_base[@]}" "mkdir -p '$REMOTE_SRC' '$REMOTE_BASE'"
|
||||||
|
|
||||||
|
rsync -az --delete \
|
||||||
|
--exclude '.git/' \
|
||||||
|
--exclude 'target/' \
|
||||||
|
--exclude '**/target/' \
|
||||||
|
--exclude '.idea/' \
|
||||||
|
--exclude '.DS_Store' \
|
||||||
|
--exclude 'build.md' \
|
||||||
|
--exclude 'node_modules/' \
|
||||||
|
-e "$rsync_ssh" \
|
||||||
|
"$REPO_ROOT/" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_SRC/"
|
||||||
|
|
||||||
|
rsync -az \
|
||||||
|
-e "$rsync_ssh" \
|
||||||
|
"$SCRIPT_DIR/deploy-likei-services.sh" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_BASE/deploy-likei-services.sh"
|
||||||
|
|
||||||
|
for cache_group in $M2_CACHE_GROUPS; do
|
||||||
|
local_cache_path="$LOCAL_M2_ROOT/$cache_group"
|
||||||
|
remote_cache_parent="$REMOTE_M2_ROOT/$(dirname "$cache_group")"
|
||||||
|
if [[ ! -d "$local_cache_path" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
"${ssh_base[@]}" "mkdir -p '$remote_cache_parent'"
|
||||||
|
rsync -az --delete \
|
||||||
|
--exclude '*.lastUpdated' \
|
||||||
|
-e "$rsync_ssh" \
|
||||||
|
"$local_cache_path" "$DEPLOY_USER@$DEPLOY_HOST:$remote_cache_parent/"
|
||||||
|
done
|
||||||
|
|
||||||
|
printf -v remote_script_q '%q' "$REMOTE_BASE/deploy-likei-services.sh"
|
||||||
|
printf -v remote_args_q '%q ' "$@"
|
||||||
|
"${ssh_base[@]}" "chmod +x $remote_script_q && $remote_script_q $remote_args_q"
|
||||||
Loading…
x
Reference in New Issue
Block a user