1

My dockerfile

FROM golang:1.18

WORKDIR /usr/src/app

COPY go.mod go.sum ./
RUN go mod download && go mod verify

COPY . .
RUN go build -o app

CMD ["./app"]

My docker-compose file

version: "3.7"

services:
 api:
 container_name: 'api'
 build: './'
 ports:
      - '8080:8080'
 volumes:
      - './:/go/src/app'
 depends_on:
      - 'mongodb'
      - 'redis'
 networks:
      - api-network
 mongodb:
 image: mongo:latest
 ports:
      - "27017:27017"
 volumes:
      - ./data/mongo:/data/db
 networks:
      - api-network
 redis:
 image: redis:alpine
 ports:
      - "6379:6379"
 volumes:
      - ./data/redis:/data
 networks:
      - api-network
networks:
 api-network:

My go code

package main

import (
    "context"
    "fmt"
    "go-redis/handler"
    "net/http"
    "os"
    "os/signal"
    "strconv"
    "time"

    "github.com/go-redis/redis/v8"
    "github.com/go-redis/redis_rate/v9"
    "github.com/labstack/echo/v4"
    "github.com/labstack/echo/v4/middleware"
    "github.com/labstack/gommon/log"
    "gopkg.in/mgo.v2"
)

var limiter *redis_rate.Limiter

func main() {
    rdb := redis.NewClient(&redis.Options{
        Addr: "redis:6379",
    })
    limiter = redis_rate.NewLimiter(rdb)
    e := echo.New()
    e.Logger.SetLevel(log.ERROR)
    e.Use(middleware.Logger())
    e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
        Level: -1,
    }))
    e.Use(middleware.JWTWithConfig(middleware.JWTConfig{
        SigningKey: []byte(handler.JWT_KEY),
        Skipper: func(c echo.Context) bool {
            // Skip authentication for signup and login requests
            if c.Path() == "/login" || c.Path() == "/signup" || c.Path() == "/all" || c.Path() == "" {
                return true
            }
            return false
        },
    }))
    e.Use(rateLimiting)
    db, err := mgo.Dial("mongodb://mongodb:27017")
    if err != nil {
        e.Logger.Fatal(err)
    }
    // Create indices
    if err = db.Copy().DB("twitter").C("users").EnsureIndex(mgo.Index{
        Key:    []string{"email"},
        Unique: true,
    }); err != nil {
        log.Fatal(err)
    }
    // Initialize handler
    h := &handler.Handler{DB: db, Rdb: rdb}

    // Routes
    e.POST("/signup", h.SignUp)
    e.POST("/login", h.SignIn)
    e.POST("/follow/:id", h.FollowUser)
    e.POST("/posts", h.NewPost)
    e.GET("/feed", h.FetchPosts)
    e.GET("/users", h.GetUsers)
    e.GET("/all", h.AllPosts)
    e.GET("/", func(c echo.Context) error {
        return c.String(http.StatusOK, "hello world")
    })

    go func() {
        // Start server
        e.Logger.Fatal(e.Start(":1323"))
    }()
    closingChannel := make(chan os.Signal, 1)
    signal.Notify(closingChannel, os.Interrupt)
    <-closingChannel
    fmt.Println("starting to shut down the server...")
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    if err := e.Shutdown(ctx); err != nil {
        fmt.Println("couldnt shut down the server...")
    }
}

func rateLimiting(next echo.HandlerFunc) echo.HandlerFunc {
    return func(c echo.Context) error {
        res, err := limiter.Allow(c.Request().Context(), "project:123", redis_rate.PerMinute(10))
        if err != nil {
            return err
        }
        h := c.Response().Header()
        h.Set("RateLimit-Remaining", strconv.Itoa(res.Remaining))
        log.Printf("Remaining %d", res.Remaining)
        if res.Allowed == 0 {
            // We are rate limited.

            seconds := int(res.RetryAfter / time.Second)
            h.Set("RateLimit-RetryAfter", strconv.Itoa(seconds))

            // Stop processing and return the error.
            return c.JSON(http.StatusTooManyRequests, "Rate limit exceeded")
        }

        // Continue processing as normal.
        return next(c)
    }
}

I get no reacable servers error. When I change hostnames with localhost and run go run main.go there are no errors but when I want to run go application in docker env and I can't connect to another container from go container.

I thought it was because mongodb is not running. But the go app depend on that so it should be running before go file got executed.

Can you help me with this problem?

Update:

I know it is not related but I changed ports in docker-compose with the same as application port which is 1323.

Still getting this error

{"time":"2022-06-08T09:19:29.1670281Z","level":"FATAL","prefix":"echo","file":"main.go","line":"47","message":"no reachable servers"}

On line 47. I am logging the error when connecting to mongodb.

  • Hi there, I guess the indentation in your compose file is _not_ as you pasted in the snippet above? That does not look correct. – Francesco Gualazzi Jun 08 '22 at 10:54
  • If there was indendation errors, the other services wouldn't be running? Because redis and mongo are up and running. – Halil Yıldırım Jun 08 '22 at 11:10
  • That mgo driver is not maintained. I think the official one is preferred: https://github.com/mongodb/mongo-go-driver. Is there a reason or limitation for using that one? – Brian Wagner Jun 08 '22 at 19:39
  • Does this answer your question? [Unable to start docker mongo image on windows](https://stackoverflow.com/questions/54911021/unable-to-start-docker-mongo-image-on-windows) – nvidot Jun 09 '22 at 13:06

1 Answers1

1

What is the host OS ?

I've tested your code (commenting out what is related to go-redis/handler) and it results that the first run is succesfull but the subsequent runs fail (though in this cases, the mongodb container fails to start) giving the exact same error message you get in the go app.

The fault happens when mongodb container is stopped and database get written to disk. If the mount for mongodb container is removed (i.e. use a docker volume) then subsequent runs are ok.

So may be the solution would be to use a docker volume in your docker compose setup.

EDIT: Unless the OP add more context, this seems as a duplicate of this and the answer is indeed related to the use of mounted volume for data persistence.

nvidot
  • 1,262
  • 1
  • 7
  • 20
  • If so, how I am reaching out the mongodb when go app is not running container? The problem with connecting to mongo only happens when go app running in the container. If I run go app out of container, just like go run main.go. There is no problem to reach out to the mongodb. – Halil Yıldırım Jun 08 '22 at 14:39
  • Well, the problem does not "only happens when go app running in the container" because as I say it is running and creating the 'twitter' collection. Are you sure that there is not another instance of mongodb running on the host? What is the host OS? Does it run the first time (`docker compose down` and swipe the relevant directory then `docker compose up`)? – nvidot Jun 08 '22 at 14:47
  • I disabled all the go-redis/handler code, as well. It works for me, both on initial run and subsequent ones. The Mongo container comes up and stays up. Of course, without handlers, it's not really doing anything else. We don't see how the handlers works, so maybe there is something in there that is relevant. – Brian Wagner Jun 08 '22 at 20:01
  • What is your host OS, Brian? – nvidot Jun 08 '22 at 22:39