203 lines
5.5 KiB
Bash
Executable File
203 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd "$script_dir/.." && pwd)"
|
|
|
|
ssh_control_path=""
|
|
cleanup() {
|
|
local exit_code=$?
|
|
|
|
if [[ -n "$ssh_control_path" ]] && ssh -o ControlPath="$ssh_control_path" -O exit "$REMOTE_HOST" >/dev/null 2>&1; then
|
|
:
|
|
fi
|
|
|
|
exit "$exit_code"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
if [[ $# -gt 1 ]]; then
|
|
echo "Usage: $0 [deploy-config-file]" >&2
|
|
exit 1
|
|
fi
|
|
|
|
config_path="${1:-$repo_root/deploy/vserver.env}"
|
|
if [[ ! -f "$config_path" ]]; then
|
|
echo "Missing deploy config: $config_path" >&2
|
|
echo "Copy deploy/vserver.env.example to deploy/vserver.env and adjust it first." >&2
|
|
exit 1
|
|
fi
|
|
|
|
set -a
|
|
source "$config_path"
|
|
set +a
|
|
|
|
REMOTE_HOST="${REMOTE_HOST:-myvserver}"
|
|
REMOTE_APP_DIR="${REMOTE_APP_DIR:-/opt/rolemasterdb}"
|
|
REMOTE_DATA_DIR="${REMOTE_DATA_DIR:-$REMOTE_APP_DIR/data}"
|
|
IMAGE_NAME="${IMAGE_NAME:-rolemasterdb}"
|
|
CONTAINER_NAME="${CONTAINER_NAME:-rolemasterdb}"
|
|
HOST_BIND_ADDRESS="${HOST_BIND_ADDRESS:-}"
|
|
HOST_PORT="${HOST_PORT:-8080}"
|
|
CONTAINER_PORT="${CONTAINER_PORT:-8080}"
|
|
REMOTE_USE_SUDO="${REMOTE_USE_SUDO:-0}"
|
|
REMOTE_ENV_FILE="${REMOTE_ENV_FILE:-}"
|
|
RELEASE_PREFIX="${RELEASE_PREFIX:-rolemasterdb}"
|
|
|
|
release_id="$(date -u +%Y%m%d%H%M%S)"
|
|
artifact_root="$repo_root/artifacts/deploy/$release_id"
|
|
stage_dir="$artifact_root/stage"
|
|
tarball_path="$artifact_root/${RELEASE_PREFIX}-${release_id}.tar.gz"
|
|
publish_dir="$repo_root/src/RolemasterDb.App/bin/Release/net10.0/publish"
|
|
seed_db_path="$repo_root/src/RolemasterDb.App/rolemaster.db"
|
|
dockerfile_path="$repo_root/deploy/vserver.Dockerfile"
|
|
project_path="$repo_root/src/RolemasterDb.App/RolemasterDb.App.csproj"
|
|
remote_release_dir="$REMOTE_APP_DIR/releases/$release_id"
|
|
remote_tarball_path="$remote_release_dir/release.tar.gz"
|
|
ssh_control_path="/tmp/rolemasterdb-deploy-${USER:-$(id -un)}-$(date -u +%Y%m%d%H%M%S)-$$.sock"
|
|
|
|
if [[ ! -f "$seed_db_path" ]]; then
|
|
echo "Seed database not found: $seed_db_path" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "$dockerfile_path" ]]; then
|
|
echo "Dockerfile not found: $dockerfile_path" >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$artifact_root"
|
|
|
|
echo "Opening shared SSH connection to $REMOTE_HOST..."
|
|
ssh \
|
|
-o ControlMaster=yes \
|
|
-o ControlPersist=10m \
|
|
-o ControlPath="$ssh_control_path" \
|
|
-Nf \
|
|
"$REMOTE_HOST"
|
|
|
|
echo "Publishing RolemasterDb.App..."
|
|
rm -rf "$publish_dir"
|
|
mkdir -p \
|
|
"$publish_dir/wwwroot/components/layout" \
|
|
"$publish_dir/wwwroot/components/shared"
|
|
env DOTNET_CLI_HOME="${DOTNET_CLI_HOME:-/tmp}" \
|
|
dotnet publish "$project_path" -c Release
|
|
|
|
echo "Preparing deploy bundle..."
|
|
rm -rf "$stage_dir"
|
|
mkdir -p "$stage_dir/publish" "$stage_dir/seed"
|
|
cp -a "$publish_dir/." "$stage_dir/publish/"
|
|
cp "$seed_db_path" "$stage_dir/seed/rolemaster.db"
|
|
cp "$dockerfile_path" "$stage_dir/Dockerfile"
|
|
tar -C "$stage_dir" -czf "$tarball_path" .
|
|
|
|
echo "Creating remote release directory..."
|
|
ssh \
|
|
-o ControlPath="$ssh_control_path" \
|
|
"$REMOTE_HOST" bash -s -- "$remote_release_dir" "$REMOTE_DATA_DIR" <<'EOF'
|
|
set -euo pipefail
|
|
release_dir="$1"
|
|
data_dir="$2"
|
|
mkdir -p "$release_dir" "$data_dir"
|
|
EOF
|
|
|
|
echo "Uploading bundle to $REMOTE_HOST..."
|
|
scp \
|
|
-o ControlPath="$ssh_control_path" \
|
|
"$tarball_path" "$REMOTE_HOST:$remote_tarball_path"
|
|
|
|
echo "Building image and restarting container on $REMOTE_HOST..."
|
|
remote_env_file_arg="${REMOTE_ENV_FILE:-__ROLEMASTERDB_EMPTY__}"
|
|
ssh \
|
|
-o ControlPath="$ssh_control_path" \
|
|
"$REMOTE_HOST" bash -s -- \
|
|
"$release_id" \
|
|
"$REMOTE_APP_DIR" \
|
|
"$REMOTE_DATA_DIR" \
|
|
"$IMAGE_NAME" \
|
|
"$CONTAINER_NAME" \
|
|
"$HOST_BIND_ADDRESS" \
|
|
"$HOST_PORT" \
|
|
"$CONTAINER_PORT" \
|
|
"$REMOTE_USE_SUDO" \
|
|
"$remote_env_file_arg" <<'EOF'
|
|
set -euo pipefail
|
|
|
|
release_id="$1"
|
|
remote_app_dir="$2"
|
|
remote_data_dir="$3"
|
|
image_name="$4"
|
|
container_name="$5"
|
|
host_bind_address="$6"
|
|
host_port="$7"
|
|
container_port="$8"
|
|
remote_use_sudo="$9"
|
|
remote_env_file="${10}"
|
|
|
|
if [[ "$remote_env_file" == "__ROLEMASTERDB_EMPTY__" ]]; then
|
|
remote_env_file=""
|
|
fi
|
|
|
|
release_dir="$remote_app_dir/releases/$release_id"
|
|
tarball_path="$release_dir/release.tar.gz"
|
|
|
|
docker_cmd=(docker)
|
|
if [[ "$remote_use_sudo" == "1" ]]; then
|
|
docker_cmd=(sudo docker)
|
|
fi
|
|
|
|
tar -xzf "$tarball_path" -C "$release_dir"
|
|
rm -f "$tarball_path"
|
|
|
|
if [[ ! -f "$remote_data_dir/rolemaster.db" ]]; then
|
|
cp "$release_dir/seed/rolemaster.db" "$remote_data_dir/rolemaster.db"
|
|
fi
|
|
|
|
"${docker_cmd[@]}" build \
|
|
-t "$image_name:$release_id" \
|
|
-t "$image_name:latest" \
|
|
"$release_dir"
|
|
|
|
"${docker_cmd[@]}" rm -f "$container_name" >/dev/null 2>&1 || true
|
|
|
|
docker_run_args=(
|
|
run
|
|
-d
|
|
--name "$container_name"
|
|
--restart unless-stopped
|
|
-e "ASPNETCORE_ENVIRONMENT=Production"
|
|
-e "ASPNETCORE_URLS=http://+:$container_port"
|
|
-e "ConnectionStrings__RolemasterDb=Data Source=/app/data/rolemaster.db"
|
|
-v "$remote_data_dir:/app/data"
|
|
)
|
|
|
|
if [[ -n "$host_bind_address" ]]; then
|
|
docker_run_args+=(-p "$host_bind_address:$host_port:$container_port")
|
|
else
|
|
docker_run_args+=(-p "$host_port:$container_port")
|
|
fi
|
|
|
|
if [[ -n "$remote_env_file" ]]; then
|
|
docker_run_args+=(--env-file "$remote_env_file")
|
|
fi
|
|
|
|
docker_run_args+=("$image_name:$release_id")
|
|
|
|
"${docker_cmd[@]}" "${docker_run_args[@]}"
|
|
|
|
ln -sfn "$release_dir" "$remote_app_dir/current"
|
|
|
|
echo "Deployment complete."
|
|
echo "Release: $release_id"
|
|
echo "Container: $container_name"
|
|
if [[ -n "$host_bind_address" ]]; then
|
|
echo "Published at: $host_bind_address:$host_port -> $container_port"
|
|
else
|
|
echo "Published at: $host_port -> $container_port"
|
|
fi
|
|
EOF
|
|
|
|
echo "Local bundle ready at $tarball_path"
|