App Engine deploy with Go libraries - google-app-engine

I'm new on Google App Engine. And, I'm getting an issue that I can't solve.
I've a very simple app (developped in Go) like this :
main/
| model/
| | user.go
| main.go
| app.yaml
These are the imports of main.go :
import (
"github.com/julienschmidt/httprouter"
"log"
"net/http"
)
My code works well when I run it locally.
But, when I try to publish it on my Google App Engine instance, I receive this error :
$ gcloud app deploy
You are about to deploy the following services:
- <MY_APP_ENGINE_URL> (from [<MY_LOCAL_YAML_PATH>])
Deploying to URL: [<MY_APP_ENGINE_URL>]
Do you want to continue (Y/n)? Y
Beginning deployment of service [default]...
Some files were skipped. Pass `--verbosity=info` to see which ones.
You may also view the gcloud log file, found at
[<LOCAL_APP_ENGINE_LOG>].
File upload done.
Updating service [default]...failed.
ERROR: (gcloud.app.deploy) Error Response: [9] Deployment contains files that cannot be compiled: Compile failed:
2017/05/27 14:48:24 go-app-builder: build timing: 5×compile (301ms total), 0×link (0s total)
2017/05/27 14:48:24 go-app-builder: failed running compile: exit status 2
main.go:4: can't find import: "github.com/julienschmidt/httprouter"
What did I do wrong ?
EDIT :
This is the content of my app.yaml file :
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app

App Engine environment doesn't contain your dependencies, you can add an script to do a go get ... for each one but it's too hacky and Go has a solution for that, we can save our dependencies in a vendor folder on the root of our project.
Quick solution:
# Instal godep:
go get -v -u github.com/tools/godep
cd your/project/path
godep save
Now try to deploy again, you'll see a vendor folder in your project, don't remove it and add it to your git source, that folder contains all your third party dependencies like your httprouter (it's my favorite :) )
Note You can use other tools to save your dependencies

I haven't used the gcloud tool, but back in the day when goapp was the tool you had to create github.com/julienschmidt/httprouter (with the lib's source in it, of course) directly under you'r main and then deploy.
AFAIK the App Engine's go version is currently 1.6 which means that while the vendoring is on by default, it can be switched off - perhaps thats the case and thats why #Yandry Pozo's suggestion doesn't work.

Related

How can I pass a variable from github actions workflow to a GAE app.yaml file?

I have a django project I want to put into maintenance mode before I update (migrate) the database.
So, my github workflow
deploys my project with a variable MAINTENANCE_MODE set to true. This new deploy I understand will reboot any running instances, ensuring all instances only show my 'Site down for maintenance' 503.html page and won't be interacting with the database.
I launch a django VM in github actions, run my migrate, run collectstatic.
I set MAINTENANCE_MODE to false, I deploy a second time. This will re-enable production server with new code that now accesses a migrated database.
My question is, I am trying to use a single app.yaml file for both deploys. To pass the MAINTENANCE_MODE variable from github actions workflow to the app.yaml file, how can I do this?
I know you can import secrets like so:
runtime: python38
instance_class: F2
env_variables:
DB_URL: $ {{ secrets.DB_URL }}
But I don't know how to modify a secret in the workflow. Perhaps its not a secret but some other type of variable one can set in the workflow and access in the app.yaml?
So it appears that Google App Engine's yaml files do not support dynamic environment variable substitution. Static substitution (like using github's secrets) works, because github compiles the file with the github environment variable before the workflow runs, but there's no clear way to modify a file with a variable that is going to change during a workflow.
A method however that does work is to compile a new GAE yaml file during the workflow. Here's what I came up with in the end...
- name: Put in Maintenance mode
run: |
MAINTENANCE_MODE=1 envsubst < app_eng_staging.yml.template > app.yaml
cat app.yaml
gcloud app deploy --project staging-project --quiet
- name: Collectstatic and migrate
env:
RUNNING_ENVIRONMENT: 'Staging_Server'
DJANGO_DEBUG: 'False'
run: |
pipenv run python manage.py collectstatic --noinput
pipenv run python manage.py migrate
- name: Turn off Maintenance and Deploy
run: |
MAINTENANCE_MODE=0 envsubst < app_eng_staging.yml.template > app.yaml
gcloud app deploy --project staging-project --quiet
The trick is to use the linux envsubst command. We start with a app_eng_staging.yml.template file, which looks like so:
runtime: python38
instance_class: F2
env_variables:
RUNNING_ENVIRONMENT: 'Staging_Server'
StagingServerDB: $ {{ secrets.STAGINGSERVER_DB }}
MAINTENANCE_MODE: ${MAINTENANCE_MODE}
FRONTEND_URL: $ {{ secrets.STAGING_FRONTEND_URL }}
envsubst then populates ${MAINTENANCE_MODE} with the value 1 and the result is saved to a new file app.yaml.
After we finish working with out database migration, we can use envsubst to create a new app.yaml with MAINTENANCE_MODE set to zero (off), and re-deploy.
Neat huh?
There is a feature in GitHub Action for this called "GAE environment variable compiler"
Please read here

Unable to provide custom app.yaml file for Java GCP App Engine project

I have a Java 11 GCP App Engine project and I'm trying to use different app.yaml files depending on the environment (e.g., app-dev.yaml, app-prod.yaml, etc). The yaml files in the /appengine directory like src/main/appengine/app-dev.yaml and so on.
There is an SO post about this already, but the answer doesn't work because it clobbers the descriptor which in Java should be the pom.xml (see my Approach 2 for more information).
Approach #1
UPDATE: Solved! In order to use this approach you must be on gcloud 298.0.0+
First, I tried using the --appyaml=APPYAML argument found in https://cloud.google.com/sdk/gcloud/reference/app/deploy#--appyaml:
gcloud app deploy [DEPLOYABLES …] [--appyaml=APPYAML] [--bucket=BUCKET] ...
I ran the following and received an error that the appyaml argument isn't recognized.
$ gcloud --project=my-project app deploy --appyaml=app-dev.yaml
ERROR: (gcloud.app.deploy) unrecognized arguments: --appyaml=app-dev.yaml
The fully qualified path to app-dev.yaml doesn't work either.
Approach #2
Next I found a slighly different syntax in https://cloud.google.com/appengine/docs/flexible/java/configuring-your-app-with-app-yaml that looks like this:
gcloud app deploy service-name-app.yaml
I tried the same locally but pointed to my custom app-dev.yaml like so, but it breaks:
$ gcloud --project=my-project app deploy src/main/appengine/app-dev.yaml
...
descriptor: [/Users/SomeDev/IdeaProjects/my-project/app-server/src/main/appengine/app-dev.yaml]
source: [/Users/SomeDev/IdeaProjects/my-project/app-server/src/main/appengine]
target project: [my-project]
target service: [default]
target version: [20200831abcdefg]
target url: [https://my-project.uc.r.appspot.com]
This breaks because it thinks the app-dev.yaml is the descriptor file instead of a pom.xml, so it errors out with the following:
Error message: did not find any jar files with a Main-Class manifest entry
To compare, I ran a normal deployment without a custom yaml file and you can see the pom.xml is the value of the descriptor.
$ gcloud --project=my-project app deploy
...
descriptor: [/Users/SomeDev/IdeaProjects/my-project/app-server/pom.xml]
source: [/Users/SomeDev/IdeaProjects/my-project/app-server]
target project: [my-project]
target service: [default]
target version: [20200831abcdefg]
target url: [https://my-project.uc.r.appspot.com]
Is there a recommended way to make this work, or is this the wrong approach entirely?
Looking at your "Approach #1" you have to upgrade your gcloud to version >= 298.0.0 here --appyaml parameter have been added - quite recently in Jun'20.
Looking at your "Approach #2". If you are running gcloud app deploy (without parameters) it search for descriptor app.yaml in current directory and if not found - than for pom.xml. If you want to use pom.xml from different localization you have to remove it from current directory. I didn't test it to the very end, just tested the descriptor value in summary.
Anyway I don't think using above is best way to do it. When you use pom.xml as descriptor it means that you are using feature called "deploy your Maven project as source code". Which is not main way to deploy app engine with maven.
According to my understanding if maven was used for build, its possible to use the jar in entrypoint of app.yaml file (reference) or maven goal appengine:deploy (reference + article that should be interesting).

Why cant go-app-builder find local imports?

I am currently writing an application in Go and trying to deploy multiple services. I am running the following command : gcloud app deploy dispatch.yaml app/app.yaml mod1/mod1.yaml.
The app.yaml file corresponds to the default service and is successfully deployed however the service mod1 returns this error:
ERROR: (gcloud.app.deploy) Error Response: [9] Deployment contains files that cannot be compiled: Compile failed: 2016/07/22 18:17:14 go-app-builder: build timing: 1×compile (53ms total), 0×link (0 total) 2016/07/22 18:17:14 go-app-builder: failed running compile: exit status 1
mod1.go:4: can't find import: "myapp/mod1/web_console"
My-Macbook: myapp$ gcloud app deploy dispatch.yaml app/app.yaml mod1/mod1.yaml
My file structure is as follows:
/My_Project
/src
/myapp
/app
app.go
app.yaml
/mod1
mod1.go
mod1.yaml
/web_console
web_console.go
mod1.go :
package mod1
import (
"myapp/mod1/web_console"
)
func init() {
// Initializing Web Console establishes connection
// to the database and also creates routes
var wc *web_console.WebConsole
wc = web_console.NewWebConsole(true)
wc.Configure()
}
mod1.yaml :
module: mod1
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app
app.yaml :
module: default
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app
Thanks for taking the time to help!
Each GAE service/module is standalone and can not access anything outside the service/module dir which:
is the directory where the .yaml file exists
is what's uploaded during deployment
is considered the "root" directory for that service/module, everything is relative to it
In your particular case you need to make sure no service/module makes references to the parent myapp dir (which is nothing but an organisational placeholder for the app stuff, relevant on your side but with no actual presence on GAE). I believe your mod1.go import should looks like this:
package mod1
import (
"web_console"
)
But take it with a grain of salt, I'm not actually familiar with go.
It seems like I was using the wrong tool to deploy. I ran the command with goapp deploy app/app.yaml mod1/mod1.yaml and was able to successfully deploy the services without issue.

bad import "syscall" for cloud storage APIs

I am following the instructions on https://cloud.google.com/appengine/docs/go/googlecloudstorageclient/download to begin migrating some code from the, now deprecated, Files API to the new Cloud Storage API without success.
The steps I'm following are ...
I'm running appengine v1.9.23 which is later than the required appengine v1.8.1.
My $GOPATH is set, so I skip step #1.
I proceed to step #2:
goapp get -u golang.org/x/oauth2
goapp get -u google.golang.org/cloud/storage
I am not developing on a managed VM, so I skip step #3.
Now when I run the application, I get:
go-app-builder: Failed parsing input: parser: bad import "syscall" in goapp/src/golang.org/x/net/internal/nettest/error_posix.go
What am I doing wrong?
Steps to reproduce
Download an install the Google Appengine runtime, version 1.9.23 from https://console.cloud.google.com/storage/browser/appengine-sdks/featured/ . Follow the installation instructions documented on https://cloud.google.com/appengine/downloads?hl=en
Create an appengine project directory:
% mkdir $HOME/myapp
Create a new app.yaml file as ~/myapp/app.yaml. Read the directions on the Google website for details: https://cloud.google.com/appengine/docs/go/config/appconfig
I use a version that does not have the static resources:
application: myapp
version: alpha-001
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app
Create a location for the Go source files.
% mkdir $HOME/myapp/go
Set your GOPATH to the location of your sources
% export GOPATH=$HOME/myapp/go
Get the Go appengine example project: https://github.com/golang/example
% goapp get github.com/golang/example/appengine-hello
This command will download the example app to the first path entry in the GOPATH
Install the Google Cloud Storage client libraries as directed in https://cloud.google.com/appengine/docs/go/googlecloudstorageclient/download . Reference the steps at the top of this question for more details. Following the directions should result in you running 2 commands:
% go get -u golang.org/x/oauth2
% go get -u google.golang.org/cloud/storage
Attempt to run your go application
% goapp serve
You will see the following compilation error (no stack trace):
2015/12/23 10:37:07 go-app-builder: Failed parsing input: parser: bad import "syscall" in go/src/golang.org/x/net/ipv6/control_unix.go
This error is caused by either of two scenarios:
1) Implicitly importing syscall by importing another package that uses it, as referenced in this related question.
2) Having your package source files in your GOPATH located in a directory at or below the same level as your project's app.yaml (eg. app.yaml in ~/go, and packages sources in ~/go/gopath/src). If a package like x/net/internal/nettest exists in your GOPATH the syscall import will be parsed by goapp at compile time and throw the compilation error.
Avoiding these two scenarios should be sufficient to prevent any bad import "syscall" errors or related compilation errors.
Reproduced the initial steps above and got a similar error, even if not explicitly mentioning syscall. However, running “goapp serve” in the appengine-hello directory results in no error at all.
Adam’s explanation at point 2 applies here correctly: one needs to place the app.yaml file at the right level in the directory structure.
sirupsen/logrus references syscall.
They have an appengine tag specified, not to include syscall so it's usable in AppEngine, something like go build -tags appengine as per issue 310.
However I haven't yet succeeded including it in an AppEngine project so that this build param could be forwarded and specified somewhere so that it goes through. I'll come back to update if I manage.

Google cloud sdks doesn't start preview for Docker image Mac OS

My app.yaml
runtime: custom
vm: true
api_version: 1
health_check:
enable_health_check: False
Dockerfile
# Use the official go docker image built on debian.
FROM golang:1.5.1
# Grab the source code and add it to the workspace.
ADD . /go/
# Install revel and the revel CLI.
RUN go get github.com/revel/revel
RUN go get github.com/revel/cmd/revel
# Use the revel CLI to start up our application.
ENTRYPOINT revel run 4quorum-appengine dev 8080
# Open up the port where the app is running.
EXPOSE 8080
I was working through this article
http://jbeckwith.com/2015/05/08/docker-revel-appengine/
Preview
I am trying to preview it:
gcloud preview app run app.yaml --custom-entrypoint "revel run 4quorum-appengine dev 8080"
WARNING: The `app run` command is deprecated and will soon be removed.
Please use dev_appserver.py (in the same directory as the `gcloud` command) instead.
Module [default] found in file [/Users/802619/Projects/src/4quorum_root/app.yaml]
INFO: Looking for the Dockerfile in /Users/802619/Projects/src/4quorum_root
INFO: Using Dockerfile found in /Users/802619/Projects/src/4quorum_root
INFO 2015-11-06 18:03:44,226 application_configuration.py:399] No version specified. Generated version id: 20151106t180344
INFO 2015-11-06 18:03:44,226 devappserver2.py:763] Skipping SDK update check.
INFO 2015-11-06 18:03:44,266 api_server.py:205] Starting API server at: http://localhost:62780
INFO 2015-11-06 18:03:44,272 dispatcher.py:197] Starting module "default" running at: http://localhost:8080
INFO 2015-11-06 18:03:44,277 admin_server.py:116] Starting admin server at: http://localhost:8000
ERROR 2015-11-06 18:03:44,282 instance.py:280] [Errno 2] No such file or directory
The same thing if trying dev_appserver.py
Deploy
Deploy also doesn't work. Fails because of timeout.
gcloud preview app deploy ./app.yaml
WARNING: Soon, deployments will set the deployed version to receive all traffic by
default.
To keep the current behavior (where new deployments do not receive any traffic),
use the `--no-promote` flag or run the following command:
$ gcloud config set app/promote_by_default false
To adopt the new behavior early, use the `--promote` flag or run the following
command:
$ gcloud config set app/promote_by_default true
Either passing one of the new flags or setting one of these properties will
silence this message.
You are about to deploy the following modules:
- vaulted-gift-112113/default (from [/Users/802619/Projects/src/4quorum_root/app.yaml])
Deployed URL: [https://20151106t204027-dot-vaulted-gift- 112113.appspot.com]
(add --promote if you also want to make this module available from
[https://vaulted-gift-112113.appspot.com])
Beginning deployment...
Verifying that Managed VMs are enabled and ready.
Provisioning remote build service.
Copying certificates for secure access. You may be prompted to create an SSH keypair.
Building and pushing image for module [default]
Saving [.dockerignore] to [/Users/802619/Projects/src/4quorum_root].
----------------------------- DOCKER BUILD OUTPUT ------------------------------
Step 0 : FROM golang:1.5.1
---> f6271e8f3723
Step 1 : ADD . /go/
---> 94fafc5e8a30
Removing intermediate container cfbe197f6e93
Step 2 : RUN go get github.com/revel/revel
---> Running in d7ad8c923144
---> b65877cf3049
Removing intermediate container d7ad8c923144
Step 3 : RUN go get github.com/revel/cmd/revel
---> Running in 2a9b3320ce47
---> 428defd008f3
Removing intermediate container 2a9b3320ce47
Step 4 : ENTRYPOINT revel run 4quorum-appengine dev 8080
---> Running in 8b9e38ec69ec
---> 3749ee8a6636
Removing intermediate container 8b9e38ec69ec
Step 5 : EXPOSE 8080
---> Running in a0e6c66b56c8
---> dafff62b9643
Removing intermediate container a0e6c66b56c8
Successfully built dafff62b9643
--------------------------------------------------------------------------------
Copying files to Google Cloud Storage...
Synchronizing files to [gs://staging.vaulted-gift-112113.appspot.com/].
Updating module [default]...|Deleted [https://www.googleapis.com/compute/v1/projects/vaulted-gift- 112113/zones/us-central1-f/instances/gae-builder-vm-20151106t204027].
Updating module [default]...failed.
ERROR: (gcloud.preview.app.deploy) Error Response: [4] Timed out creating VMs.
About to drop this.
Moved to heroku. Google App Engine is not ready yet.

Resources