Create a remote developer environment in GCP and manage with Github Actions
Tags: gcp, tutorial, productivity, cloud
Published: 2023-05-29 15:45:47

## Why a Remote Developer environment?

My laptop, which runs Linux, is an old machine that I use for side projects. There isn't much memory or processing power for running Docker containers or virtual machines. In order to avoid buying a costly laptop at this time, I have decided to set up a remote development environment. Remote environments offer several advantages including: the ability to access the environment from multiple machines; the ability to modify the OS, RAM, and CPU to meet your specific needs; and you don't have to install as many dev tools on your local machine, which helps if you have limited space. Furthermore, remote environments are often much cheaper to set up than buying a new laptop, making them a great option for budget-conscious developers. 

## GCP

The cloud provider I chose was Google Cloud Provider (GCP) since they offered 300 dollars in free credits to first-time users; but, you could set up a development environment in any cloud provider if you have a strong preference.  I found the overall experience of using GCP to be really pleasant and GCP provides some really slick tools to streamline setup. The instructions below will be specific to GCP.

## Get started with GCP

To get started you will need to create an account if you don't have one already. Once you have created an account, be sure to enter a credit card to be able to use all the features. 

- Next, create a project. I called my project DevEnv
- In the newly created project, click on the navigation menu. Click on Compute Engine and select VM instances. 
![GCP Menu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofmwj4ge4xgmj0v1nk5q.jpg)
- Click on Create an instance.
- Name your instance whatever you like. I called mine dev. 
- Select the region and zone. 
- Configure the Memory and CPU to meet your needs. 
- For the boot disk I chose an Ubuntu Image and chose 50gb for the size. You can change this to suit your needs.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k79n844jhbku99gmeocp.jpg)
- With everything configured, you can click on create and after a few minutes your newly created VM will come up. 

## Install GPC CLI
You will need to install the Google Cloud CLI on your local machine. 
I followed these [instructions](https://cloud.google.com/sdk/docs/install
).
When you run the initial gcloud init command, target the project you created and the instance you created.


## Connect to your environment

In the VM instance dashboard, 

- Click the drop down SSH button and select the view gcloud command. This will bring up a command you can copy and paste into your terminal. 
- Connect to your VM using the command provided. 

## Inside your VM

If you want to customize your shell and install development tools on your VM, you may want root access. If so, please follow these [instructions](https://cloud.google.com/compute/docs/connect/root-ssh).

You can also add your user to the sudoers file. To do so, follow these steps: 
- Log in as root
- Run `vim /etc/sudoers`
- Replicate the line `root ALL=(ALL:ALL) ALL`, replace root with your username, and save the file. (You’ll need to save with :w! since the file is readonly.)
- Log back in as your user.

Now you have a VM and know how to connect to it. You can install whatever development tools you like. 

## Remote connection through VS Code

To ease interaction with the VM I downloaded VS Code onto my local machine and installed the GCP plugin and the Remote .SSH plugin. 

The GCP plugin provides some helpful tooling to help you quickly create cloud applications and makes developing Kubernetes Apps easier. If you plan on doing any of this type of development I would recommend you check it out [here](https://cloud.google.com/code/docs/vscode/get-started-k8s).

[Remote SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) allows you to connect VS Code to your VM so you can edit code easily while using your preferred themes and plugins. To connect to your VM with Remote SSH do the following:

- Open VSCode and press ⌘ + Shift + P for macOS or Ctrl + Shift + P for Linux/Window to open VSCode Command Palette. 
- Type in Remote-SSH and select `Add New SSH Host`. 
![Add new SSH Host](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a8a7zraoe2cc8av9690d.jpg)
- In the "Enter SSH Connection" command prompt that pops up, type : `ssh -i ~/.ssh/[KEY_FILENAME] [USERNAME]@[External IP]` and press Enter. The [KEY_FILENAME] should be the key created by the gcloud CLI and the same one you used to originally connect to the VM. 
![VS Code ssh connect](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9orwq0p1jlf5xnqipxmy.jpg)
- You can now open the command palette and type remote-ssh again. 
- This time select Connect to  host. The IP of your VM should pop up and you can click on it to open a new window connected to the VM file system. 

If you do web development you may want to port forward so that changes in the code are reflected in the browser. To do this there is a small button that looks like a radio tower at the bottom of the VS Code console.  Click on it and click "Forward a Port'. Type in the port number and the local address. I am forwarding port 1313 in this example. So when I type localhost:1313, my application will load in the browser.
![Port Forward](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ziekb5lgf9jtxbyu9dxk.jpg) 
![Forward to localhost](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oaq20a9qs7iqr9izv41i.jpg)

## Github Actions to manage VM

I can only work on my side projects sporadically and I don't want to keep the VM running when I'm not actively developing. To help me manage my VM I created a Github Action that suspends the VM every night if it's running. Suspending a VM will keep it around but you won't be charged for it. While the VM is suspended, Google only charges for the storage used to preserve its memory. 

Below is the workflow I used.

```yaml
name: Suspend VM

# Controls when the workflow will run
on:
  schedule:
    # Runs "at 10pm every day"
    - cron: '0 22  *'
  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  suspend-vm:
    # Add "id-token" with the intended permissions.
    permissions:
      contents: 'read'
      id-token: 'write'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      # Configure Workload Identity Federation via a credentials file.
      - id: 'auth'
        name: 'Authenticate to Google Cloud'
        uses: 'google-github-actions/auth@v1'
        with:
          workload_identity_provider: ${{ secrets.PROVIDER }}
          service_account: ${{ secrets.SERVICE_ACCOUNT }}
      # Install gcloud, `setup-gcloud` automatically picks up authentication from `auth`.
      - name: 'Set up Cloud SDK'
        uses: 'google-github-actions/setup-gcloud@v1'
      # Now you can run gcloud commands authenticated as the impersonated service account.
      - id: 'gcloud-describe'
        name: 'gcloud describe'
        run: |
             echo "status=$(gcloud compute instances describe 'dev' \
            --project ${{ vars.PROJECT }} \
            --zone ${{ vars.zone }} \
            --format='value(status)')" >> $GITHUB_OUTPUT

      # Only run suspend if the VM is running
      - if: steps.gcloud-describe.outputs.status == 'RUNNING'
        name: 'gcloud suspend'
        run: |
           gcloud compute instances suspend "dev" \
           --project ${{ vars.PROJECT }} \
           --zone ${{ vars.zone}}


      - if: steps.gcloud-describe.outputs.status != 'RUNNING'
        name: 'automation not needed'
        run: echo "Dev env is not running"
```
Let's break down what this file does. 

First, we tell Github we want to run this on a schedule and manually. 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jw6v6ssk37x33w6kudxs.jpg)

We define one job, suspend-VM and give it the permissions needed for OIDC. 
![Define Github Action Job](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cwwhs6b5sghaza4epigm.jpg)

The first step is to check out the repository. We then use the [google-github-actions/auth](https://github.com/google-github-actions/auth) action.
This requires setting up OIDC on GitHub and Google Cloud. For more details, see [here](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-google-cloud-platform) and [here](https://cloud.google.com/iam/docs/workload-identity-federation?_ga=2.114275588.-285296507.1634918453#conditions). 
![OIDC in Github Actions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qxqnus2bmprxo2ui1o0m.jpg) 


The next step uses the [google-github-actions/setup-gcloud](https://github.com/marketplace/actions/set-up-gcloud-cloud-sdk-environment) action. This action is handy because it automatically picks up the authentication setup in the last step.
![Set up Gcloud](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eot0jbhqo2plsuvexglq.jpg)

Next we run a describe command to check if the VM is running. Note: We send the response to GITHUB_OUTPUT. 
![gcloud CLI command to get VM status](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/htfatqrjqdwyb89cuzq8.jpg)

The next two steps use the if condition to determine if they should be run.
In the first case, suspend the VM if it is running. 
![Suspend Gcloud VM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1lq32yneqiz3mozdo794.jpg)

The second case is if the VM is not running. Here we echo a message indicating there was no need to suspend the VM.
![Conditional Github Action](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qxbxuug7km3lw970prms.jpg)

And there you have it. A nightly job make sure I'm not spending more money than I need to be. 

## Summary
This whole process was fairly easy. However, I had to spend some time understanding how GCP handles OIDC (a bit different from AWS). The docs [here](https://github.com/marketplace/actions/authenticate-to-google-cloud#setup) and [here](https://cloud.google.com/iam/docs/workload-identity-federation) helped a lot. GCP also has this cool tool called [Policy Troubleshooter](https://cloud.google.com/policy-intelligence/docs/troubleshoot-access) that helped me identify that I had forgotten to add the suspend permission to my created role.  

The remote environment, some handy plugins in VS Code, and Github Actions automation have made for a pretty enjoyable development experience for me. With all these tools at my disposal, I have been able to quickly and effectively address any development issues that arise. It has been a smooth and productive ride so far, and I'm thankful for the modern tools that I have to work with. If you are familiar with remote development environments or know of any other tooling that makes this experience better, let me know in the comments. 

_Photo by Rafael Cerqueira: https://www.pexels.com/photo/blue-and-white-sky-with-stars-4737484/z_