Skip to content

CLI Deployment Guide

This guide covers the complete procedure to deploy the Video Upload Pipeline from your local machine using the terminal. This is the recommended method for production updates to ensure configuration consistency.

1. Build and Tag the Image

We build the image locally and push it to the Google Artifact Registry. Cloud Run cannot pull images from your laptop; it pulls from this registry.

1.1. Build the image Navigate to the root of the project and build the Docker image.

# Example tag: livekit-pipeline-local
sudo docker build -f pkg/google-cloud-uploader/Dockerfile -t livekit-pipeline-local .

1.2. Verify the build (Optional) You can run the container locally to ensure it starts without crashing.

sudo docker run --rm -p 8080:8080 \
  -e PORT=8080 \
  -e LIVEKIT_API_KEY=test \
  -e LIVEKIT_API_SECRET=test \
  livekit-pipeline-local node dist/service.js

2. Push to Artifact Registry

2.1. Prepare GCP CLI Ensure you are logged in and targeting the correct project.

gcloud auth login
gcloud config set project video-uploader-480122

2.2. Create the Repository (First Time Only) If the repository containers does not exist in Artifact Registry:

gcloud artifacts repositories create containers \
    --repository-format=docker \
    --location=us-central1 \
    --description="Video Pipeline Repository"

2.3. Tag the image We must tag the local image with the full remote path format: LOCATION-docker.pkg.dev/PROJECT_ID/REPO/IMAGE:TAG.

# Replace :v16 with your new version number
docker tag livekit-pipeline-local us-central1-docker.pkg.dev/video-uploader-480122/containers/qubital-pipeline:v16

2.4. Authenticate Docker with GCP This command pipes a temporary Google access token into the Docker login command. This avoids storing permanent credentials.

gcloud auth print-access-token | sudo docker login -u oauth2accesstoken --password-stdin https://us-central1-docker.pkg.dev

2.5. Push the image

docker push us-central1-docker.pkg.dev/video-uploader-480122/containers/qubital-pipeline:v15

3. Service Account Setup

We follow the Least Privilege Principle. We create a specific Service Account (SA) that the Service uses to identify itself and trigger the Job.

3.1. Create the Service Account (First Time Only)

gcloud iam service-accounts create video-sa --display-name="Video Pipeline Service Account"

3.2. Export SA Email Save this variable to use in the deployment commands below.

export SA_EMAIL="video-sa@video-uploader-480122.iam.gserviceaccount.com"

4. Deploy the Cloud Run Job

The Job is the "Worker" that performs the heavy lifting. It executes dist/job.ts.

Secrets Management

In the command below, ensure you replace the values with the actual production secrets. Do not commit real API keys to version control.

gcloud run jobs deploy video-upload-job \
  --image us-central1-docker.pkg.dev/video-uploader-480122/containers/qubital-pipeline:v15 \
  --region us-central1 \
  --service-account $SA_EMAIL \
  --command node \
  --args dist/job.js \
  --tasks 1 \
  --max-retries 0 \
  --task-timeout 60m \
  --memory 2Gi \
  --set-env-vars LIVEKIT_URL="wss://qubital-lk-4raif9fl.livekit.cloud/",\
LIVEKIT_API_KEY="...",\
LIVEKIT_API_SECRET="...",\
GOOGLE_CLIENT_ID="...",\
GOOGLE_CLIENT_SECRET="...",\
GOOGLE_REFRESH_TOKEN="...",\
GOOGLE_SHEET_ID="...",\
R2_BUCKET="qubital-storage",\
R2_ENDPOINT="https://b0c7740ea3c51309f74e94cbe625b502.r2.cloudflarestorage.com",\
R2_ACCESS_KEY="...",\
R2_SECRET_KEY="...",\
SLACK_BOT_TOKEN="...",\
SLACK_CHANNEL_ID="#video-call-archive"

5. Deploy the Cloud Run Service

The Service is the "Listener" that receives WebHooks. It executes dist/service.js.

gcloud run deploy livekit-listener \
  --image us-central1-docker.pkg.dev/video-uploader-480122/containers/qubital-pipeline:v15 \
  --region us-central1 \
  --service-account $SA_EMAIL \
  --command node \
  --args dist/service.js \
  --allow-unauthenticated \
  --set-env-vars JOB_NAME="video-upload-job",\
GOOGLE_CLOUD_PROJECT=video-uploader-480122,\
GOOGLE_CLOUD_REGION="us-central1",\
LIVEKIT_API_KEY="...",\
LIVEKIT_API_SECRET="..."

6. Connect Permissions

This is the most critical step. By default, the Service cannot trigger the Job. We must explicitly grant the video-sa Service Account permission to invoke the Job.

# Grant "Invoker" permission
gcloud run jobs add-iam-policy-binding video-upload-job \
  --region us-central1 \
  --member "serviceAccount:$SA_EMAIL" \
  --role "roles/run.invoker"

# Grant "Developer" permission (Required for override execution)
gcloud run jobs add-iam-policy-binding video-upload-job \
  --region us-central1 \
  --member "serviceAccount:$SA_EMAIL" \
  --role "roles/run.developer"

7. Updating the Application

When you have new code (e.g., v17), you do not need to re-type all the secrets. You can update just the image reference.

Step 1: Push new image

docker build ... -t ...:v16
docker push ...:v16

Step 2: Update Service

gcloud run deploy livekit-listener \
  --image us-central1-docker.pkg.dev/video-uploader-480122/containers/qubital-pipeline:v16 \
  --region us-central1

Step 3: Update Job

Note: We use jobs update here, not jobs deploy

gcloud run jobs update video-upload-job \
  --image us-central1-docker.pkg.dev/video-uploader-480122/containers/qubital-pipeline:v16 \
  --region us-central1