golang Infinite for loop problem with docker run - docker

I tried to do simple infinite for loop task. It is working fine without using docker. But when i used the docker,it only executes the else part of for loop infinitely. What may be problem actually? Is docker having problem with infinite for loop?
My main.go file is shown below.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
fmt.Println("Hello, World!.....")
for {
fmt.Print("-> ")
var i int
fmt.Scan(&i)
if i == 1 {
fmt.Println("Hello, World! 1")
} else if i == 2 {
fmt.Println("Hello, World! 2")
} else if i == 3 {
fmt.Println("Hello, World! 3")
} else if i == 4 {
fmt.Println("Hello, World! 4")
} else if i == 5 {
fmt.Println("Hello, World! 5")
} else {
fmt.Println("Hello, World! else")
}
}
}
I tried these link as well. Read line in golang How do I break out of an infinite loop in Golang But still of no use. I am trying to solve the problem since yesterday.
The docker file is as given below:
FROM golang:1.12.0-alpine3.9
RUN mkdir /app
ADD . /app
WORKDIR /app
RUN go build -o main .
CMD ["go","run","/app/main.go"]
I tried to build the docker using
docker build -t hello .
and run using docker run hello
Running with
docker run hello
Executing with console without docker go run main.go

The infinite loop is because your go program is waiting for an input and you're not launching the container in interactive mode.
To make it work you need to use this command (note the -it option) :
docker container run --rm --name hello -it hello

Scan returns an error. It is likely that no data is read and i is 0 (as that is the zero value of an int).
Change your code to panic in case of no data:
var i int
_, err := fmt.Scan(&i)
if err != nil {
panic(err)
}
The Go playground behaves in a similar way.

Related

Deploy Go Lambda within Docker container

I have a Go Lambda function. I want to host that function in a Docker image/container so that I can test it locally. In this effort, I have followed the instructions provided here. From those instructions, I have the following files:
.
Dockerfile
go.mod
go.sum
main.go
Those files contain the following:
Dockerfile (a copy of the Dockerfile in this section)
FROM alpine as build
# install build tools
RUN apk add go git
RUN go env -w GOPROXY=direct
# cache dependencies
ADD go.mod go.sum ./
RUN go mod download
# build
ADD . .
RUN go build -o /main
# copy artifacts to a clean image
FROM alpine
COPY --from=build /main /main
ENTRYPOINT [ "/main" ]
go.mod (an updated version of this go.mod)
module main
go 1.18
require (
github.com/aws/aws-lambda-go v1.32.1
github.com/aws/aws-sdk-go v1.44.60
)
require github.com/jmespath/go-jmespath v0.4.0 // indirect
go.sum (a modified version of this go.sum)
github.com/aws/aws-lambda-go v1.32.1 h1:ls0FU8Mt7ayJszb945zFkUfzxhkQTli8mpJstVcDtCY=
github.com/aws/aws-lambda-go v1.32.1/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM=
github.com/aws/aws-sdk-go v1.44.60 h1:KTTogelVR+4dWiIPl7eyxoxaJkziChON6/Y/hVfTipk=
github.com/aws/aws-sdk-go v1.44.60/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
main.go (a copy of this main.go)
package main
import (
"context"
"encoding/json"
"log"
"os"
"github.com/aws/aws-lambda-go/events"
runtime "github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-lambda-go/lambdacontext"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/lambda"
)
var client = lambda.New(session.New())
func callLambda() (string, error) {
input := &lambda.GetAccountSettingsInput{}
req, resp := client.GetAccountSettingsRequest(input)
err := req.Send()
output, _ := json.Marshal(resp.AccountUsage)
return string(output), err
}
func handleRequest(ctx context.Context, event events.SQSEvent) (string, error) {
// event
eventJson, _ := json.MarshalIndent(event, "", " ")
log.Printf("EVENT: %s", eventJson)
// environment variables
log.Printf("REGION: %s", os.Getenv("AWS_REGION"))
log.Println("ALL ENV VARS:")
for _, element := range os.Environ() {
log.Println(element)
}
// request context
lc, _ := lambdacontext.FromContext(ctx)
log.Printf("REQUEST ID: %s", lc.AwsRequestID)
// global variable
log.Printf("FUNCTION NAME: %s", lambdacontext.FunctionName)
// context method
deadline, _ := ctx.Deadline()
log.Printf("DEADLINE: %s", deadline)
// AWS SDK call
usage, err := callLambda()
if err != nil {
return "ERROR", err
}
return usage, nil
}
func main() {
runtime.Start(handleRequest)
}
I can successfully run:
go mod tidy
go build
I can also successfully build and run my Docker image using:
docker build -t lambda-fn .
docker run -d -v ~/.aws-lambda-rie:/aws-lambda --entrypoint /aws-lambda/aws-lambda-rie -p 9000:8080 lambda-fn:latest /main
I can see a container based on the lambda-fn image listed, with a status of Running, in Docker desktop. However, when I send the following cURL request, nothing happens:
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
I was expecting some logs to be written based on the contents of the handleRequest function. What am I doing wrong?
If you are running in demon mode (-d) you cannot see the logs.
Remove -d and rerun the command
This is due the empty handler registration. You can set the handler name by passing the extra argument
docker run -d -v ~/.aws-lambda-rie:/aws-lambda --entrypoint /aws-lambda/aws-lambda-rie -p 9000:8080 lambda-fn:latest /main handleRequest

How to Spin up docker container & run some command via golang script?

I am planning to automate spinning up container and run some commands on it.
But I get the below error
docker run -it alpine sh ls
Error I get is
docker error : the input device is not a TTY.
So I removed interactive part and ran
docker run -t alpine sh ls
I don't get the shell but docker is spinning
I run above docker commands in golangs os.exec package.
package main
import (
"fmt"
"os"
"os/exec"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
cmd := exec.Command("docker", "run","-it","alpine","sh","ls")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
// log.Println(cmd.Run())
}()
}()
wg.Wait()
}
My intention is to run multiple shell scripts after spinning up the docker.
Any help would be appreciated. Thanks
One avenue to explore is the official packages moby/moby integration-cli and moby/moby integration-cli/cli with cli.go.
The func Docker(cmd icmd.Cmd, cmdOperators ...CmdOperator) *icmd is made to run a docker command, with parameters.
Example, for docker run:
cli.Docker(cli.Args("run", "--name", name, "--rm", "busybox", "sh", "-c", "sleep 30; echo hi"))

Connect to docker container that runs golang server using netcat

I'm new to docker. Trying to create an image from a simple server written in golang. Server listens on port 8000 and writes current time to the client once per second.
package main
import (
"fmt"
"io"
"net"
"time"
)
func main() {
listener, err := net.Listen("tcp", "localhost:8000")
if err != nil {
panic(err)
}
for {
conn, err := listener.Accept()
fmt.Println("Received connection")
if err != nil {
fmt.Println(err)
continue
}
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
defer conn.Close()
for {
_, err := io.WriteString(conn, time.Now().Format("15:04:05\n"))
if err != nil {
return
}
time.Sleep(1 * time.Second)
}
}
My Dockerfile
FROM golang
WORKDIR $GOPATH/src/
RUN mkdir -p sandbox/clock1
WORKDIR $GOPATH/src/sandbox/clock1
COPY . .
RUN go get -d -v ./...
RUN go install -v ./...
EXPOSE 8000
ENTRYPOINT /go/bin/clock1
I start docker container with command
docker run -p 8000:8000 -it --name clock1 clock1
And then I'm trying to connect to server using docker IP address
nc 192.168.1.3 8000
netcat fails to connect and exists immediately. Could you please point me to what I'm doing wrong.

Go binary not found when using Dockerfile

I am following Go's Docker instructions. Their example works for me. I am now trying to modify it to run a tcp server:
go get github.com/Kelindar/tcp
Add a Dockerfile:
FROM golang
ADD . /go/src/github.com/Kelindar/tcp
RUN go install github.com/Kelindar/tcp
ENTRYPOINT /go/bin/tcp
EXPOSE 8080
I then build it:
docker build --no-cache -t tcp .
build output:
Sending build context to Docker daemon 322kB
Step 1/5 : FROM golang
---> 9fe4cdc1f173
Step 2/5 : ADD . /go/src/github.com/Kelindar/tcp
---> 10abce658324
Step 3/5 : RUN go install github.com/Kelindar/tcp
---> Running in 59dc47b30474
Removing intermediate container 59dc47b30474
---> 8fab53d2882c
Step 4/5 : ENTRYPOINT /go/bin/tcp
---> Running in 18d4b5befccb
Removing intermediate container 18d4b5befccb
---> 073fdb78a481
Step 5/5 : EXPOSE 8080
---> Running in 8ee2b7bc0cba
Removing intermediate container 8ee2b7bc0cba
---> 8bf9f82d4fef
Successfully built 8bf9f82d4fef
Successfully tagged tcp:latest
Now, I run it:
docker run --name test --rm tcp
I get an error:
/bin/sh: 1: /go/bin/tcp: not found
Not really sure where to go on this.
There are two problems here:
The package github.com/Kelindar/tcp does not contain a main function, thus it can't produce a binary to be executed.
There is no main package, and every go program needs a main package with a main function
Whether you run go build or go install in this repository, you will see that nothing will happen, since your package is actually a library.
Now if you add a cmd/tcp_server folder with a tcp_server.go file like this:
package main
import (
"fmt"
"log"
"net"
"github.com/kelindar/tcp"
)
func main() {
closingChan := make(chan bool)
onAccept := func(c net.Conn) {
// Do something here.
}
l, err := net.Listen("tcp", fmt.Sprintf(":%d", 4242))
if err != nil {
log.Fatalf("Unable to net.Listen: %v", err)
}
server := &tcp.Server{
Closing: closingChan,
OnAccept: onAccept,
}
log.Println("Server ready...")
if err := server.Serve(l); err != nil {
log.Fatalf("Server crashed: %v", err)
}
log.Println("Server stopped")
}
And that you update your Dockerfile to use the command that uses your tcp package:
FROM golang
RUN go get github.com/Kelindar/tcp
RUN go build -o $GOPATH/bin/tcp_server $GOPATH/src/github.com/Kelindar/tcp/cmd/tcp_server/tcp_server.go
ENTRYPOINT tcp_server
EXPOSE 8080
Your server will be working properly within docker:
2019/06/16 05:23:29 Server ready...

Running microservice go (not found)

The error I'm getting for my Go Module project
/bin/sh: microservice: not found
Dockerfile
FROM golang:1.7.4-alpine
MAINTAINER John Doe
ENV SOURCES /go/src/github.com/john/app/
COPY . ${SOURCES}
RUN cd ${SOURCES} && cgo_enabled=0 go install
ENV PORT 8080
EXPOSE 8080
ENTRYPOINT microservice
microservice.go
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
http.HandleFunc("/", index)
http.ListenAndServe(port(), nil)
}
func port() string {
port := os.Getenv("PORT")
fmt.Println(port)
if len(port) == 0 {
port = "8080"
}
return ":" + port
}
func index(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Hello World.")
}
It's a Go module project. I've created an image using following command.
docker build -t app:1.0.3 .
and running it via
docker run -it -p 8080:8080 app:1.0.3
Created executable file is at /go/bin/app
and current working directory is /go.
So, change the last line of your Dockerfile to this
ENTRYPOINT ./bin/app

Resources