.../articles/
Setting Up a GAE/Go Development Environment

Setting Up a GAE/Go Development Environment

2019.03.19

Last time, I wrote about the code for implementing an authenticated API with GAE/Go and Firebase. This time, building on that code, I'll summarize how to set up an environment for developing with GAE/Go and Firebase.


Local development environment

Code for GAE can be run locally using a command called dev_appserver.py. Authentication is required to deploy, but it's not needed just to run things locally.

Also, to match the GAE/Go environment, I'm using Go version 1.11.

Setting up this kind of development environment is fine to leave to each individual, but when multiple people are developing together, everyone's environment ends up with some differences, and it's a hassle to go back and forth whenever something changes. So I generally use Docker to keep the development environment consistent.

On package management

For Go package management, I initially assumed I'd use dep, but there was information about running into issues when deploying to GAE (and I did in fact run into them), and since Modules — while still in a transitional period — was becoming usable, I decided to use Modules instead.

Docker environment for GAE/Go

What's needed is an environment where the minimum required commands for Go 1.11 can run, so I prepared a Dockerfile based on golang:1.11.6 that just installs gcloud and golangci-lint.

# Dockerfile
FROM golang:1.11.6

RUN apt-get update -y && \
    apt-get install lsb-release -y

RUN export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
    echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
    apt-get update -y && \
    apt-get install google-cloud-sdk google-cloud-sdk-app-engine-python google-cloud-sdk-app-engine-go google-cloud-sdk-datastore-emulator -y

RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.15.0

WORKDIR /go/src/YOUR_VCS/YOUR_NAME/YOUR_REPO

Replace /YOUR_VCS/YOUR_NAME/YOUR_REPO with your own environment's values.

Write the necessary environment variables into .env, and set up docker-compose.yml as follows.

GO111MODULE is set to enable the use of Modules mentioned above, and GOOGLE_APPLICATION_CREDENTIALS is set so that Firebase credentials can be loaded from JSON.

# .env
GO111MODULE=on
GOOGLE_APPLICATION_CREDENTIALS=/go/src/YOUR_VCS/YOUR_NAME/YOUR_REPO/app/serviceAccountKey.json
# docker-compose.yml
version: '3'

services:
  go:
    build: dockerfiles/go
    env_file:
      - .env
    volumes:
      - .:/go/src/YOUR_VCS/YOUR_NAME/YOUR_REPO
    ports:
      - 8080:8080
      - 8000:8000
    restart: 'no'
    command: make serve

The docker-compose.yml command is set to make serve, which is defined in the Makefile as follows.

# Makefile
serve:
	dev_appserver.py app.yaml --host=0.0.0.0 --admin_host=0.0.0.0 --support_datastore_emulator=False

At this point, the directory structure looks like this. serviceAccountKey.json has been downloaded from the Firebase console (and already added to .gitignore).

.
├── .env
├── .gitignore
├── Makefile
├── README.md
├── app
│   ├── main.go
│   └── serviceAccountKey.json
├── app.yaml
├── docker-compose.yml
├── dockerfiles
│   └── go
│       └── Dockerfile
├── go.mod
└── go.sum

Here's app.yaml at its bare minimum for now.

# app.yaml
runtime: go111

main: app
handlers:
- url: /.*
  script: auto
  secure: always

With that, we're ready to spin up the development environment with docker-compose.

$ docker-compose up
# Now accessible at localhost:8080, localhost:8000

dev_appserver.py detects code changes and builds automatically, and when a build runs it pulls in any required Modules on its own — so from here you can just write code in your editor of choice. (That said, getting editor support tools like formatters working is still something each person needs to sort out for themselves.)


Deploying to GAE

If you've already completed the authentication setup with the gcloud command as described above, deploying is as simple as a single command.

$ gcloud app deploy app.yaml

Almost too easy.


Using CircleCI

Since I wanted CircleCI to handle various things whenever code was pushed, I put together the following config file for now.

# .circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: golang:1.11.6
        environment:
          GO111MODULE: 'on'
    working_directory: /go/src/YOUR_VCS/YOUR_NAME/YOUR_REPO
    steps:
      - checkout
      - restore_cache:
          key: modules-{{ checksum "go.mod" }}
      - run:
          name: install modules
          command: go mod tidy
      - save_cache:
          key: modules-{{ checksum "go.mod" }}
          paths:
            - /go/pkg/mod
      - run:
          name: lint
          command: |
            curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.15.0
            golangci-lint run --verbose
      - run:
          name: build
          command: go build app/main.go

This just checks that the code passes the default golangci-lint linter settings and that it builds, so from here I'm planning to add testing and deployment into the mix.

About caching Modules

CircleCI is set up to cache Modules, saving the downloaded Modules under /go/pkg/mod keyed on the checksum of go.mod.

Regarding this: since using Modules generates both go.mod and go.sum, I somehow assumed — based on the feel of other package managers — that go.sum was a so-called lock file, but it turns out that's not the case.

According to the wiki, go.sum is not a lock file, and reproducible builds are possible with go.mod alone, so I set key: modules-{{ checksum "go.mod" }}.


With this, the environment from local development, through deployment, to CI has been set up.

Both GAE and Go seem to be evolving quickly, so I plan to keep catching up on new information and improving things little by little.

written by

.../article/

Articles

All articles

From Firebase to Vercel, Contentful to microCMS — a migration log written with Claude Code

From Firebase to Vercel, Contentful to microCMS — a migration log written with Claude Code

We moved our corporate site's hosting and CMS, and made it bilingual along the way. The constraints we only found by running against real data were more useful than the migration itself, so this post focuses on where we got stuck.

Can't Read POST Data with Firebase Functions × Remix?

Can't Read POST Data with Firebase Functions × Remix?

How to read POST data from a Remix action when running on Firebase Functions.

Generative AI for Executives and Leaders: An Approach to Self-Driven DX

Generative AI for Executives and Leaders: An Approach to Self-Driven DX

Building a structure where executives and leaders themselves can identify issues and evaluate solutions using generative AI. We introduce how combining this with our hands-on support dramatically improves both the quality and speed of digital transformation.

Deploying a Monorepo Next.js App (App Router) to AWS Amplify

Deploying a Monorepo Next.js App (App Router) to AWS Amplify

Notes on the obstacles we hit while deploying a Next.js app managed in a monorepo to AWS Amplify.

Keeping Production Running Smoothly with Remote Work and Online Meetings [Documentation]

Keeping Production Running Smoothly with Remote Work and Online Meetings [Documentation]

Many production companies have adopted remote work as a result of the pandemic, and we are one of them.

Designing an E-Commerce Site That Sells: How to Find Great Reference Examples

Designing an E-Commerce Site That Sells: How to Find Great Reference Examples

There is no single formula for e-commerce design that sells. Driving revenue requires a solid concept, and getting to that concept requires thorough research.

Productivity Tools We Recommend as a Production Company, Including Services That Work Well Solo

Productivity Tools We Recommend as a Production Company, Including Services That Work Well Solo

With remote work becoming the norm during the COVID-19 pandemic, our team now works from home most days of the week.

We Released Thought Recorder, a Figma Plugin for Keeping a Commit History of Your Designs

We Released Thought Recorder, a Figma Plugin for Keeping a Commit History of Your Designs

We hope this helps web designers who work in Figma. Read on for how to use it.

How to Build an E-Commerce Site, and Which Platforms We Recommend

How to Build an E-Commerce Site, and Which Platforms We Recommend

Shopping online for fashion, appliances, and even groceries is now routine. With the pandemic accelerating the shift, we receive a steady stream of questions about which platform to use and how much it costs.

Generating FastAPI Schema Classes from OpenAPI

Generating FastAPI Schema Classes from OpenAPI

We chose FastAPI, a relatively modern framework, for a Python API project. FastAPI can generate an OpenAPI definition from your backend code, but here we do the opposite: generating FastAPI schema classes from an OpenAPI definition prepared in advance.

View all articles

Contact us