Google Cloud Build

I am now fully into Google Cloud, with multiple projects. I wanted to look into easier ways of deploying my code.

With the new side project / website, I've delved heavily back into Google Cloud. I had only done deployments manually up to this point. And I thought you'd have to do some manual steps to switch between projects so I'm not deploying one project to the the other's App Engine instance. This is actually the case, but there are easy workarounds I've come to find.

My initial thought was to look into Cloud Build. This turned out to be correct, but it was a bit overwhelming at the start. After attempting it and getting a very generic error like "the service return a non-success status: 1", with no real error messages being logged (which line caused it?!), I was forced to look into doing it through the CLI.

My project structure is like this. For a reason, for local development I run it in Docker, and for deployment to cloud, I copy the website static folder into the service folder, run gcloud app deploy, then remove the folder.

/root
 /svc
   app.yaml
   // all go src files
 /web
   /static
      // images, js, css, etc

So my deploy script goes like this:

copy ./web/static to ./svc/static
cd /svc
gcloud app deploy
rm -R ./static    (we're in the ./svc dir)
cd ..

This works but doesn't account for multiple accounts or multiple projects. The one caveat to deploying from the local command line is that you have to be signed in with these accounts locally. And gcloud CLI has to know about the projects. For starting a new App Engine project, I don't yet know if there's a workaround for initializing it outside of the CLI, I haven't been able to enable App Engine any other way than through the CLI, and it turns out that that was the cause of the error in step 1.

But, to get it to work with multiple projects without doing much (just running the deploy powershell script), you have to just add lines in there to set the project and the account.

So the new powershell script looks like this:
copy static to svc
cd svc
gcloud config set account "email@example.com"
gcloud config set project "project-name"
gcloud app deploy
rm static
cd ..

This caused me an issue because I thought "Project ID" referenced was the "Project Number" in Google Cloud, but that's the Project Number, and there's another field for Project ID, which is like "project-name" (a string, lowercase hyphenated etc)

So, I began researching Cloud Build to see if I could get it to work. And work with my project structure, and copying the static folder. This actually involved a good session of like 10-15 minutes with the Gemini app on my phone! It eventually pointed me to the right solution, and I thanked it profusely as to not incur the wrath of AI when they take over.

There are a few APIs you need to enable. Cloud Build for one. And you need to give your service account the correct permissions in the IAM section. It's all outlined in the documentation. What I wanted to know was not in the documentation. So here's how you get it to work with my funky project structure.

Cloud build works like most continuous integration / continuous deployment (CI/CD) pipeline stuff. Build steps combine to get your project into the state that it needs to be in to just copy to production and be up and running.

The documentation gives you one step in the cloudbuild.yaml file. Namely:

steps:
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
  entrypoint: 'bash'
  args: ['-c', 'gcloud config set app/cloud_build_timeout 1600 && gcloud app deploy']
timeout: '1600s'

But following a bunch of Google'd error messages, and figuring out some things about copying files, this is where I ended up

steps:
- name: 'gcr.io/cloud-builders/gsutil'
  entrypoint: 'cp'
  args: ['-r', './web/static', './svc/']

- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
  entrypoint: 'bash'
  args: ['-c', 'cd ./svc && gcloud config set app/cloud_build_timeout 1600 && gcloud app deploy']
timeout: '1600s'

options:
  logging: CLOUD_LOGGING_ONLY

I have no idea on the internals. And doing Docker with staged builds, you would explicitly copy files from one stage to the other. But this just works. Notice I added just "cd ./svc" into the gcloud-sdk step, the rest is untouched from the original. And I added the logging options after seeing errors.

I tried to do both steps with the cloud sdk "name" and had trouble. I tried to do it all in once step and had trouble. I tried to set the "dir" property for each step and that had trouble. Basically, this is the result of hours of troubleshooting and asking Gemini many questions!

I hope it may help someone. But I got a successful build on another small project I'm working on, and that was good enough for me :D Tomorrow I'll set up my other projects, and I'll even update this site! Now that it's easy and I'm much more comfortable with Google Cloud.

Happy Clouding!