Deploy collab like nightly (#7174)
After this change we'll be able to push a tag to github to deploy to collab. The advantages of this are that there's no longer a separate step to first build the image, and then deploy it. In the future I'd like to make this happen more automatically (maybe as part of bump nightly). Release Notes: - N/A
This commit is contained in:
parent
5424c8bfd5
commit
7b9d51929d
9 changed files with 188 additions and 115 deletions
107
.github/workflows/deploy_collab.yml
vendored
Normal file
107
.github/workflows/deploy_collab.yml
vendored
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
name: Publish Collab Server Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- collab-production
|
||||||
|
- collab-staging
|
||||||
|
|
||||||
|
env:
|
||||||
|
DOCKER_BUILDKIT: 1
|
||||||
|
DIGITALOCEAN_ACCESS_TOKEN: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
style:
|
||||||
|
name: Check formatting and Clippy lints
|
||||||
|
runs-on:
|
||||||
|
- self-hosted
|
||||||
|
- test
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
clean: false
|
||||||
|
submodules: "recursive"
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Run style checks
|
||||||
|
uses: ./.github/actions/check_style
|
||||||
|
|
||||||
|
tests:
|
||||||
|
name: Run tests
|
||||||
|
runs-on:
|
||||||
|
- self-hosted
|
||||||
|
- test
|
||||||
|
needs: style
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
clean: false
|
||||||
|
submodules: "recursive"
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
uses: ./.github/actions/run_tests
|
||||||
|
|
||||||
|
publish:
|
||||||
|
name: Publish collab server image
|
||||||
|
needs:
|
||||||
|
- style
|
||||||
|
- tests
|
||||||
|
runs-on:
|
||||||
|
- self-hosted
|
||||||
|
- deploy
|
||||||
|
steps:
|
||||||
|
- name: Add Rust to the PATH
|
||||||
|
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Sign into DigitalOcean docker registry
|
||||||
|
run: doctl registry login
|
||||||
|
|
||||||
|
- name: Prune Docker system
|
||||||
|
run: docker system prune --filter 'until=720h' -f
|
||||||
|
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
clean: false
|
||||||
|
submodules: "recursive"
|
||||||
|
|
||||||
|
- name: Build docker image
|
||||||
|
run: docker build . --build-arg GITHUB_SHA=$GITHUB_SHA --tag registry.digitalocean.com/zed/collab:$GITHUB_SHA
|
||||||
|
|
||||||
|
- name: Publish docker image
|
||||||
|
run: docker push registry.digitalocean.com/zed/collab:${GITHUB_SHA}
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
name: Deploy new server image
|
||||||
|
needs:
|
||||||
|
- publish
|
||||||
|
runs-on:
|
||||||
|
- self-hosted
|
||||||
|
- deploy
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Sign into Kubernetes
|
||||||
|
run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 ${{ secrets.CLUSTER_NAME }}
|
||||||
|
|
||||||
|
- name: Determine namespace
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
if [[ $GITHUB_REF_NAME = "collab-production" ]]; then
|
||||||
|
echo "Deploying collab:$GITHUB_SHA to production"
|
||||||
|
echo "KUBE_NAMESPACE=production" >> $GITHUB_ENV
|
||||||
|
elif [[ $GITHUB_REF_NAME = "collab-staging" ]]; then
|
||||||
|
echo "Deploying collab:$GITHUB_SHA to staging"
|
||||||
|
echo "KUBE_NAMESPACE=staging" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "cowardly refusing to deploy from an unknown branch"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Start rollout
|
||||||
|
run: kubectl -n "$KUBE_NAMESPACE" set image deployment/collab collab=registry.digitalocean.com/zed/collab:${GITHUB_SHA}
|
||||||
|
|
||||||
|
- name: Wait for rollout to finish
|
||||||
|
run: kubectl -n "$KUBE_NAMESPACE" rollout status deployment/collab
|
49
.github/workflows/publish_collab_image.yml
vendored
49
.github/workflows/publish_collab_image.yml
vendored
|
@ -1,49 +0,0 @@
|
||||||
name: Publish Collab Server Image
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- collab-v*
|
|
||||||
|
|
||||||
env:
|
|
||||||
DOCKER_BUILDKIT: 1
|
|
||||||
DIGITALOCEAN_ACCESS_TOKEN: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish:
|
|
||||||
name: Publish collab server image
|
|
||||||
runs-on:
|
|
||||||
- self-hosted
|
|
||||||
- deploy
|
|
||||||
steps:
|
|
||||||
- name: Add Rust to the PATH
|
|
||||||
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Sign into DigitalOcean docker registry
|
|
||||||
run: doctl registry login
|
|
||||||
|
|
||||||
- name: Prune Docker system
|
|
||||||
run: docker system prune
|
|
||||||
|
|
||||||
- name: Checkout repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
clean: false
|
|
||||||
submodules: 'recursive'
|
|
||||||
|
|
||||||
- name: Determine version
|
|
||||||
run: |
|
|
||||||
set -eu
|
|
||||||
version=$(script/get-crate-version collab)
|
|
||||||
if [[ $GITHUB_REF_NAME != "collab-v${version}" ]]; then
|
|
||||||
echo "release tag ${GITHUB_REF_NAME} does not match version ${version}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Publishing collab version: ${version}"
|
|
||||||
echo "COLLAB_VERSION=${version}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Build docker image
|
|
||||||
run: docker build . --tag registry.digitalocean.com/zed/collab:v${COLLAB_VERSION}
|
|
||||||
|
|
||||||
- name: Publish docker image
|
|
||||||
run: docker push registry.digitalocean.com/zed/collab:v${COLLAB_VERSION}
|
|
|
@ -6,6 +6,9 @@ COPY . .
|
||||||
|
|
||||||
# Compile collab server
|
# Compile collab server
|
||||||
ARG CARGO_PROFILE_RELEASE_PANIC=abort
|
ARG CARGO_PROFILE_RELEASE_PANIC=abort
|
||||||
|
ARG GITHUB_SHA
|
||||||
|
|
||||||
|
ENV GITHUB_SHA=$GITHUB_SHA
|
||||||
RUN --mount=type=cache,target=./script/node_modules \
|
RUN --mount=type=cache,target=./script/node_modules \
|
||||||
--mount=type=cache,target=/usr/local/cargo/registry \
|
--mount=type=cache,target=/usr/local/cargo/registry \
|
||||||
--mount=type=cache,target=./target \
|
--mount=type=cache,target=./target \
|
||||||
|
|
|
@ -3,3 +3,35 @@
|
||||||
This crate is what we run at https://collab.zed.dev.
|
This crate is what we run at https://collab.zed.dev.
|
||||||
|
|
||||||
It contains our back-end logic for collaboration, to which we connect from the Zed client via a websocket after authenticating via https://zed.dev, which is a separate repo running on Vercel.
|
It contains our back-end logic for collaboration, to which we connect from the Zed client via a websocket after authenticating via https://zed.dev, which is a separate repo running on Vercel.
|
||||||
|
|
||||||
|
# Local Development
|
||||||
|
|
||||||
|
Detailed instructions on getting started are [here](https://zed.dev/docs/local-collaboration).
|
||||||
|
|
||||||
|
# Deployment
|
||||||
|
|
||||||
|
We run two instances of collab:
|
||||||
|
|
||||||
|
* Staging (https://staging-collab.zed.dev)
|
||||||
|
* Production (https://collab.zed.dev)
|
||||||
|
|
||||||
|
Both of these run on the Kubernetes cluster hosted in Digital Ocean.
|
||||||
|
|
||||||
|
Deployment is triggered by pushing to the `collab-staging` (or `collab-production`) tag in Github. The best way to do this is:
|
||||||
|
|
||||||
|
* `./script/deploy-collab staging`
|
||||||
|
* `./script/deploy-collab production`
|
||||||
|
|
||||||
|
You can tell what is currently deployed with `./script/what-is-deployed`.
|
||||||
|
|
||||||
|
# Database Migrations
|
||||||
|
|
||||||
|
To create a new migration:
|
||||||
|
|
||||||
|
```
|
||||||
|
./script/sqlx migrate add <name>
|
||||||
|
```
|
||||||
|
|
||||||
|
Migrations are run automatically on service start, so run `foreman start` again. The service will crash if the migrations fail.
|
||||||
|
|
||||||
|
When you create a new migration, you also need to update the [SQLite schema](./migrations.sqlite/20221109000000_test_schema.sql) that is used for testing.
|
||||||
|
|
|
@ -14,6 +14,7 @@ use tracing_subscriber::{filter::EnvFilter, fmt::format::JsonFields, Layer};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||||
|
const REVISION: Option<&'static str> = option_env!("GITHUB_SHA");
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
|
@ -26,7 +27,7 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
match args().skip(1).next().as_deref() {
|
match args().skip(1).next().as_deref() {
|
||||||
Some("version") => {
|
Some("version") => {
|
||||||
println!("collab v{VERSION}");
|
println!("collab v{} ({})", VERSION, REVISION.unwrap_or("unknown"));
|
||||||
}
|
}
|
||||||
Some("migrate") => {
|
Some("migrate") => {
|
||||||
run_migrations().await?;
|
run_migrations().await?;
|
||||||
|
@ -105,7 +106,7 @@ async fn run_migrations() -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_root() -> String {
|
async fn handle_root() -> String {
|
||||||
format!("collab v{VERSION}")
|
format!("collab v{} ({})", VERSION, REVISION.unwrap_or("unknown"))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_liveness_probe(Extension(state): Extension<Arc<AppState>>) -> Result<String> {
|
async fn handle_liveness_probe(Extension(state): Extension<Arc<AppState>>) -> Result<String> {
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [[ $# < 1 ]]; then
|
|
||||||
echo "Missing version increment (major, minor, or patch)" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec script/lib/bump-version.sh collab collab-v '' $1
|
|
|
@ -3,22 +3,19 @@
|
||||||
set -eu
|
set -eu
|
||||||
source script/lib/deploy-helpers.sh
|
source script/lib/deploy-helpers.sh
|
||||||
|
|
||||||
if [[ $# < 2 ]]; then
|
if [[ $# != 1 ]]; then
|
||||||
echo "Usage: $0 <production|staging> <tag-name>"
|
echo "Usage: $0 <production|staging>"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
environment=$1
|
environment=$1
|
||||||
version=$2
|
tag="$(tag_for_environment $environment)"
|
||||||
|
|
||||||
export_vars_for_environment ${environment}
|
branch=$(git rev-parse --abbrev-ref HEAD)
|
||||||
image_id=$(image_id_for_version ${version})
|
if [ "$branch" != "main" ]; then
|
||||||
|
echo "You must be on main to run this script"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
export ZED_DO_CERTIFICATE_ID=$(doctl compute certificate list --format ID --no-header)
|
echo git pull --ff-only origin main
|
||||||
export ZED_KUBE_NAMESPACE=${environment}
|
echo git tag -f $tag
|
||||||
export ZED_IMAGE_ID=${image_id}
|
echo git push -f origin $tag
|
||||||
|
|
||||||
target_zed_kube_cluster
|
|
||||||
envsubst < crates/collab/k8s/collab.template.yml | kubectl apply -f -
|
|
||||||
kubectl -n "$environment" rollout status deployment/collab --watch
|
|
||||||
|
|
||||||
echo "deployed collab v${version} to ${environment}"
|
|
||||||
|
|
|
@ -8,33 +8,30 @@ function export_vars_for_environment {
|
||||||
export $(cat $env_file)
|
export $(cat $env_file)
|
||||||
}
|
}
|
||||||
|
|
||||||
function image_id_for_version {
|
|
||||||
local version=$1
|
|
||||||
|
|
||||||
# Check that version is valid
|
|
||||||
if [[ ! ${version} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
||||||
echo "Invalid version number '${version}'" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check that image exists for version
|
|
||||||
tag_names=$(doctl registry repository list-tags collab --no-header --format Tag)
|
|
||||||
if ! $(echo "${tag_names}" | grep -Fqx v${version}); then
|
|
||||||
echo "No docker image tagged for version '${version}'" >&2
|
|
||||||
echo "Found images with these tags:" ${tag_names} >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "registry.digitalocean.com/zed/collab:v${version}"
|
|
||||||
}
|
|
||||||
|
|
||||||
function version_for_image_id {
|
|
||||||
local image_id=$1
|
|
||||||
echo $image_id | cut -d: -f2
|
|
||||||
}
|
|
||||||
|
|
||||||
function target_zed_kube_cluster {
|
function target_zed_kube_cluster {
|
||||||
if [[ $(kubectl config current-context 2> /dev/null) != do-nyc1-zed-1 ]]; then
|
if [[ $(kubectl config current-context 2> /dev/null) != do-nyc1-zed-1 ]]; then
|
||||||
doctl kubernetes cluster kubeconfig save zed-1
|
doctl kubernetes cluster kubeconfig save zed-1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function tag_for_environment {
|
||||||
|
if [[ "$1" == "production" ]]; then
|
||||||
|
echo "collab-production"
|
||||||
|
elif [[ "$1" == "staging" ]]; then
|
||||||
|
echo "collab-staging"
|
||||||
|
else
|
||||||
|
echo "Invalid environment name '${environment}'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function url_for_environment {
|
||||||
|
if [[ "$1" == "production" ]]; then
|
||||||
|
echo "https://collab.zed.dev"
|
||||||
|
elif [[ "$1" == "staging" ]]; then
|
||||||
|
echo "https://collab-staging.zed.dev"
|
||||||
|
else
|
||||||
|
echo "Invalid environment name '${environment}'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
|
@ -3,13 +3,15 @@
|
||||||
set -eu
|
set -eu
|
||||||
source script/lib/deploy-helpers.sh
|
source script/lib/deploy-helpers.sh
|
||||||
|
|
||||||
if [[ $# < 1 ]]; then
|
if [[ $# != 1 ]]; then
|
||||||
echo "Usage: $0 <production|staging>"
|
echo "Usage: $0 <production|staging>"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
environment=$1
|
|
||||||
|
|
||||||
export_vars_for_environment ${environment}
|
environment=$1
|
||||||
|
url="$(url_for_environment $environment)"
|
||||||
|
tag="$(tag_for_environment $environment)"
|
||||||
|
|
||||||
target_zed_kube_cluster
|
target_zed_kube_cluster
|
||||||
|
|
||||||
deployed_image_id=$(
|
deployed_image_id=$(
|
||||||
|
@ -20,18 +22,9 @@ deployed_image_id=$(
|
||||||
| cut -d: -f2
|
| cut -d: -f2
|
||||||
)
|
)
|
||||||
|
|
||||||
job_image_ids=$(
|
echo "Deployed image version: $deployed_image_id"
|
||||||
kubectl \
|
|
||||||
--namespace=${environment} \
|
|
||||||
get jobs \
|
|
||||||
-o 'jsonpath={range .items[0:5]}{.spec.template.spec.containers[0].image}{"\n"}{end}' \
|
|
||||||
2> /dev/null \
|
|
||||||
|| true
|
|
||||||
)
|
|
||||||
|
|
||||||
echo "Deployed image version:"
|
git fetch >/dev/null
|
||||||
echo "$deployed_image_id"
|
if [[ "$(git rev-parse tags/$tag)" != $deployed_image_id ]]; then
|
||||||
echo
|
echo "NOTE: tags/$tag $(git rev-parse tags/$tag) is not yet deployed"
|
||||||
echo "Migration job image versions:"
|
fi;
|
||||||
echo "$job_image_ids"
|
|
||||||
echo
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue