In this article I’m going to show the process I followed to migrate some of the services I used from Google Cloud to an European provider, in this case OVH. I won’t use their cloud solution, but their VPS offering instead, in order to have full control over the infrastructure.1
In particular, I will show how I moved out from Cloud SQL to a self hosted instance of PostgreSQL, how I moved the Cloud Run services to a more standard nginx setup, and how reached the same level of CI/CD I had with Google Cloud.
The migrated service is fitsleepinsights.app: a custom dashboard for Fitbit users, with RAG support (gemini-based) for chatting with your data and getting insights about your fitness activities and sleep data. The service is fully open source, and the code is available on GitHub.
The reasons
There are two main reasons why I decided to move the service from Google Cloud to OVH. The first one is purely economical: the costs of the Cloud SQL instance were too high. I was paying too much for the very minimal setup of the instance, which delivered very poor performance.
The second reason is political. It’s my first small step of “getting back to the EU” to reduce dependency on US companies.
The CI/CD pipeline
The CI/CD pipeline is similar to what I had with Google Cloud, but now it’s hosted on GitHub Actions.
Instead of deploying to the cloud, I deploy the service on a VPS. The end result is the same: the service is deployed in seconds, but at a much lower cost.
Additionally, since we are deploying a Go application that compiles to self-contained binaries, the deployment is very fast and doesn’t require any external dependencies or containerization.
For the sake of completeness, I’m going to show the Github Actions workflow for the Google Cloud and the OVH VPS.
The Google Cloud CI/CD pipeline
The Github Actions workflow is the following:
- Checkout the code
- Authenticate to Google Cloud Artifact Registry
- Build the application inside a Docker container
- Push the application to the Artifact Registry
- Deploy the application to the Cloud Run service
This of course requires a cloud side configuration, with a lot of clicks, and regions limitations.
e.g. for automatize the deploy of the cloud run service under the domain fitsleepinsights.app
(registered on Google Domains), I had to re-configure the cloud run service in order to be in a region compatible with the domain (see the CLOUD_RUN_REGION
variable in the YAML file below).
The cloud run service itself had to be configured by specifying all the parameters related to the cold start, the environment variables, the secrets, the VPC, the service account, etc.
So, the deploy is not the YAML file you see below, but a mix of YAML and clicks on the Google Cloud Console (and a ton of trial and error). Anyway, I leave the YAML file below for the sake of completeness.
name: Build and Deploy to Cloud Run
on:
push:
branches: [ main ]
# The secrets have been defined inside the Github settings
# The env vars MUST be defined here to be accessible with env.VAR
env:
GAR_LOCATION: europe-west6
PROJECT_ID: train-and-deploy-experiment
CLOUD_RUN_REGION: europe-west1 # must be 1 to support google domain
REPOSITORY: fitsleep-actions-repo
SERVICE: fitsleep-actions-cloudrun-service
jobs:
deploy:
permissions:
contents: 'read'
id-token: 'write'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Google Auth
id: auth
uses: 'google-github-actions/auth@v2'
with:
token_format: 'access_token'
workload_identity_provider: '${{ secrets.WIF_PROVIDER }}'
service_account: '${{ secrets.WIF_SERVICE_ACCOUNT }}'
- name: Docker Auth
id: docker-auth
uses: 'docker/login-action@v3'
with:
username: 'oauth2accesstoken'
password: '${{ steps.auth.outputs.access_token }}'
registry: '${{ env.GAR_LOCATION }}-docker.pkg.dev'
- name: Build and Push Container
run: |-
docker build -t "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}" ./
docker push "${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}"
- name: Deploy to Cloud Run
id: deploy
uses: google-github-actions/deploy-cloudrun@v2
with:
service: ${{ env.SERVICE }}
region: ${{ env.CLOUD_RUN_REGION }}
image: ${{ env.GAR_LOCATION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.SERVICE }}:${{ github.sha }}
- name: Show Output
run: echo ${{ steps.deploy.outputs.url }}
The OVH VPS CI/CD pipeline
Unlike cloud services where configuration is done through web interfaces with many clicks, the OVH VPS CI/CD pipeline requires some traditional Linux system administration.
The prerequisites
The prerequisite steps to run on the VPS are straightforward:
- Install Go
- Install PostgreSQL
- Install nginx
- Install Certbot (Optional, right now I’m still using Cloudflare for automatic HTTPS certificates)
May seem a lot, but in the end it’s just a single command (sudo apt install postgresql nginx certbot
), and the configuration of the services at startup. Literally, 5 minutes.
Since this is a service migration, we need to migrate the database as well. Cloud SQL is a managed PostgreSQL instance, so we need to migrate it to a self hosted Postg