How can I deploy beego app to Heroku - heroku

I'm creating a web app in beego that I need to have running in Heroku.
I can get it running normally if I just specify the binary for the app in the Procfile. But I want to have swagger available in the app, so I need to use bee to start the app like:
bee run -downdoc=true -gendoc=true
so that it automatically creates and downloads all the swagger related icons, html, etc.
But, if I specify that as the command in Procfile (even after adding bee to vendor so that it is available), it fails because the app doesn't have the go command available in runtime. The exact error is this:
0001 There was an error running 'go version' command: exec: "go": executable file not found in $PATH
How can I bypass this without adding the whole swagger specification to heroku (and github, since it is a repository)?

You can not run bee command on heroku, because it is a executable program.
But you can run beego app on heroku with adding project dependencies. In order to that you should use tools like https://github.com/kardianos/govendor.
1. After install govendor try following steps in your project folder;
$ govendor init
This command will create ./vendor/vendor.json file in current directory.
{
"comment": "https://github.com/ismailakbudak/beego-api-example",
"heroku": {
"install" : [ "./..." ],
"goVersion": "go1.11"
},
"ignore": "test",
"package": [],
"rootPath": "reporting-api"
}
Add heroku tag like above example. There is a information about this configuration on heroku docs in here https://devcenter.heroku.com/articles/go-dependencies-via-govendor#build-configuration
2. After this add beego package dependency with this command
$ govendor fetch github.com/astaxie/beego
It will download the beego packages to ./vendor directory
3. Lastly you should configure listen ports and beego runmode as prod for heroku in main.go file
To deploy your app without problem, default config must be runmode = prod in conf/app.conf. I tried to set it default as dev and change it from heroku config vars as below, but it compiles packages before the set runmode and gives exception with this message panic: you are running in dev mode.
func main() {
log.Println("Env $PORT :", os.Getenv("PORT"))
if os.Getenv("PORT") != "" {
port, err := strconv.Atoi(os.Getenv("PORT"))
if err != nil {
log.Fatal(err)
log.Fatal("$PORT must be set")
}
log.Println("port : ", port)
beego.BConfig.Listen.HTTPPort = port
beego.BConfig.Listen.HTTPSPort = port
}
if os.Getenv("BEEGO_ENV") != "" {
log.Println("Env $BEEGO_ENV :", os.Getenv("BEEGO_ENV"))
beego.BConfig.RunMode = os.Getenv("BEEGO_ENV")
}
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/"] = "swagger"
beego.Run()
}
You can use BEEGO_ENV=dev bee run to continue develop your app without change it again

Related

Go app (in docker container) not reflecting changes on page?

I'm new to Go, but having an annoying issue where changes in the code are not reflected on the page, unless I do another --build when I bring up the container. Is this normal? I'm running`Windows 10, Go 1.19, AMD, Docker Desktop/Compose.
If I change "Hello, World!" to some other string, CTRL+C the running app, and then run docker-compose up, the changes are NOT reflected on the page, even after clearing browser cache and using an incognito window. HOWEVER, if I run docker-compose up --build, the changes WILL be reflected.
Reminder I'm new to Go, but is this normal behaviour? Do I have to re-build the project in docker-compose each time to see the changes? Or do you see anything "off" in my code? I'm following a few year old Udemy course, so of course every step there's a new "thing" to troubleshoot as it doesn't work as shown eye roll
They suggest using Air for hot-reloading, which I'm also having an issue with as IT'S not working either, however I've opened a GitHub issue for that.
Here is the code from the various files:
main.go
package main
import (
"ambassador/src/database"
"github.com/gofiber/fiber/v2"
)
func main() {
// Connect to the database
database.Connect()
// Migrate tables in the database
database.AutoMigrate()
// Create a new fiber app, which is based on Express.js
app := fiber.New()
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
app.Listen(":3000")
}
Dockerfile
FROM golang:1.19
WORKDIR /app
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
# Use air for live go hot-reloading
# This one doesn't work, use go install instead
# RUN curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
# Air does not work for me. Opening github issue. Skip for now
# RUN go install github.com/cosmtrek/air#latest
# CMD ["air"]
CMD ["go", "run", "main.go"]
docker-compose.yaml
version: '3.9'
services:
backend:
build: .
ports:
- 8000:3000
# volumes:
# - .:/app
depends_on:
- db
db:
image: mysql:5.7.22
restart: always
environment:
MYSQL_DATABASE: ambassador
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_ROOT_PASSWORD: root
volumes:
- .dbdata:/var/lib/mysql
ports:
- 33066:3306
src > database > db.go
package database
import (
"ambassador/src/models"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func Connect() {
var err error
DB, err = gorm.Open(mysql.Open("root:root#tcp(db:3306)/ambassador"), &gorm.Config{})
if err != nil {
panic("Could not connect with the database!")
}
}
func AutoMigrate() {
DB.AutoMigrate(models.User{})
}
src > models > user.go
package models
type User struct {
Id uint
FirstName string
LastName string
Email string
Password string
IsAmbassador bool
}
go.mod
module ambassador
go 1.19
require github.com/gofiber/fiber/v2 v2.36.0
require (
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.15.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.38.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect
gorm.io/driver/mysql v1.3.5 // indirect
gorm.io/gorm v1.23.8 // indirect
)
The same code is included in this screenshot of my IDE.
Go isn’t a script language and needs in rebuild and restart application to apply changes
You can use Golang fresh for rebuild and restart your app
https://github.com/gravityblast/fresh
Add this to your Dockerfile
RUN go install github.com/pilu/fresh#latest
...
CMD [ "fresh" ]
You are not mounting any files into your container, only copying them once on image build. This is why you are not seeing anychanges unless you build, or copy new files into the container.
You've already commented out a volume from your docker-compose.yaml, but if you uncomment those lines you should see that changes are reflected without rebuilding.
To answer your original question — NO, you DO NOT need to add the --build tag when running up your docker-compose file. It doesn't relate to Go, it relates only to docker containers working logic.
If we come to the live-reload problem then the problem is with the technology docker uses for file sharing between a host system and containers.
I have had the same issues on mac when tried to use not the Docker Desktop but an alternative like Rancher which even uses docker CLI via moby. When I switched back to the original Docker Desktop which uses gRPC FUSE, osxfs, and VirtioFS — with all of them worked like a charm.
I don't know how this feature is implemented on windows, but I'm sure you could dig into this direction.

Terraform / Heroku not finding 'web' process in heroku/ruby buildpack

I'm getting an error in Terraform:
Error: Patch "https://api.heroku.com/apps/coderdojo-contentful-staging/formation/web": Couldn't find that process type (web).
│
│ with heroku_formation.coderdojo_contentful_staging_formation[0],
│ on terraform.tf line 41, in resource "heroku_formation" "coderdojo_contentful_staging_formation":
│ 41: resource "heroku_formation" "coderdojo_contentful_staging_formation" {
from these lines from my terraform.tf file:
resource "heroku_formation" "coderdojo_contentful_staging_formation" {
count = length(var.formations)
app = heroku_app.coderdojo_contentful_staging.name
type = lookup(var.formations[count.index], "type")
quantity = lookup(var.formations[count.index], "quantity")
size = lookup(var.formations[count.index], "size")
}
which rely on these lines in my terraform.tfvars file:
formations = [
{
type = "web"
size = "standard-1x"
quantity = "1"
}
]
buildpacks = [
"heroku/ruby"
]
Searching the documentation online (e.g. buildpacks and heroku-buildpack-ruby) it appears that the web process type comes from either the buildpack, or the Procfile.
Another project works fine with a very similar setup (i.e. no Procfile), but with the addition of a heroku/nodejs buildpack. I tried adding that build pack but got the same error.
What am I missing?
Another project works fine with a very similar setup (i.e. no Procfile), but with the addition of a heroku/nodejs buildpack. I tried adding that build pack but got the same error.
The heroku/nodejs buildpack falls back to the start script defined in the package.json if no Procfile is present. I suspect your other project that uses that buildpack has a start script. The Ruby buildpack has no such default.
If your app doesn't require Node.js, don't add the Node.js buildpack. Instead, add a Procfile to the root of your repository that tells Heroku how to run your app, e.g.
web: bundle exec ruby path/to/some/script.rb
This defines a web process that runs bundle exec ruby ruby path/to/some/script.rb.

How to read env files by runnnig Go application?

I have an application which is developed in Go. I have a config.env file and get some critical variables from it by using the godotenv library. Here is the code:
func InitializeEnvVars() error {
err := godotenv.Load("./config.env")
return err
}
When I build my project with go build . on MacOS and I want to run the application, the app gives an error about reading the .env file:
2021/03/07 17:42:21 [ERROR]: Error loading .env file
But when I run my app with go run main.go command, everything works well.
How can I solve this problem?
As per the comments godotenv.Load("./config.env") will attempt to load the .env file from the working directory. The method used to set the working directory depends upon how you are starting the application (i.e. command line/gui).
If you would prefer that the .env be loaded from the folder holding the executable then try the following (note that there are some caveats).
ex, err := os.Executable()
if err != nil {
panic(fmt.Sprintf("Failed to get executable path: %s", err))
}
envPath := filepath.Join(filepath.Dir(ex), ".env")
err = godotenv.Load(envPath)
You can find the solution below step by step:
Create a folder like cmd
Move executable file to the folder
Create env file with written named in the code into this folder
Open terminal (zsh - MacOS) and run this command: open <executableFileName>
Output file should be in separated folder.

Why does terraformer not find plugin?

I am new to the world of terraform. I am trying to use terraformer on a GCP project, but keep getting plugin not found:
terraformer import google --resources=gcs,forwardingRules,httpHealthChecks --connect=true --
regions=europe-west1,europe-west4 --projects=myproj
2021/02/12 08:17:03 google importing project myproj region europe-west1
2021/02/12 08:17:04 google importing... gcs
2021/02/12 08:17:05 open \.terraform.d/plugins/windows_amd64: The system cannot find the path specified.
Prior to the above, installed terraformer thus: choco install terraformer I downloaded the Google provider, terraform-provider-google_v3.56.0_x5.exe, placed it in my terraform dir, and did terraform init. I checked %AppData\Roaming\terraform.d\plugins\windows_amd64 and the plugins\windows_amd64 did not exist, so I created it, dropped in the Google exe and redid the init.
My main.tf was:
provider "google" {
project = "{myproj"
region = "europe-west2"
zone = "europe-west2-a"
}
Could it be the chocolatey install causing this issue? I have never used it before but the alternative install looks daunting!
If you install from Chocolatey, it seems it looks for the provider files at C:\.terraform.d\plugins\windows_amd64. If you create those directories and drop the terraform-provider-xxx.exe file in there it will be picked up.
I would also suggest running it with the --verbose flag.
Remember to execute "terraform init"
Once you install the terraformer, check this
Create the versions.tf file
versions.tf example
terraform {
required_providers {
google = {
source = "hashicorp/aws"
}
}
required_version = ">= 0.13"
}
Execute terraform init
Start the import process, something like:
terraformer import aws --profile [my-aws-profile] --resources="*" --regions=eu-west-1
Where --resources="*" will get everything from aws, but you could specify route53 or other resources
terraformer import aws --profile [my-aws-profile] --resources="route53" --regions=eu-west-1
The daunting instructions worked!
Run git clone <terraformer repo>
Run go mod download
Run go build -v for all providers OR build with one provider go run build/main.go {google,aws,azure,kubernetes and etc}
Run terraform init against an versions.tf file to install the plugins required for your platform. For example, if you need plugins for the google provider, versions.tf should contain:
terraform {
required_providers {
google = {
source = "hashicorp/google"
}
}
required_version = ">= 0.13"
}
making sure to run that version and not the chocolatey one.
go mod download the flag -x will give output while that command runs, otherwise you might think nothing is happening.

How to get Go detailed build logs, with all used packages in GOPATH and "go module" mode?

I have situation with a project.
It behave different when i use go module, outside GOPATH, and "go get" inside GOPATH. In both cases build goes without errors.
But GPRC connection behaves differently. Gives timeout in "go mod" case, works fine with "go get".
I suspect that go uses different set of packages. I need full list of used packages with versions in both modes to compare. How can i access it?
For listing installed packages using GOPATH, please see this old thread: How to list installed go packages
The following applies to the new module mode.
At compile / build time
You may use the go list -m all command to view final versions that will be used in a build for all direct and indirect dependencies (source). You can read more details about this here: Modules: Version Selection.
At runtime
At runtime (from your application) you may use the debug.ReadBuildInfo() function:
ReadBuildInfo returns the build information embedded in the running binary. The information is available only in binaries built with module support.
Note: debug.ReadBuildInfo() was only added in Go 1.12 (released just a day ago).
Example getting and printing build info (recursively). Easiest is to JSON-marshal the build info:
bi, ok := debug.ReadBuildInfo()
if !ok {
fmt.Println("Getting build info failed (not in module mode?)!")
return
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(bi); err != nil {
panic(err)
}
Example output
Example output for a project which has a single dependency: github.com/globalsign/mgo).
Running go list -m all:
mytest
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
Getting and JSON-marshaling the build info at runtime:
{
"Path": "mytest",
"Main": {
"Path": "mytest",
"Version": "(devel)",
"Sum": "",
"Replace": null
},
"Deps": [
{
"Path": "github.com/globalsign/mgo",
"Version": "v0.0.0-20181015135952-eeefdecb41b8",
"Sum": "h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=",
"Replace": null
}
]
}

Resources