skip to Main Content

I have a Go app that does basic CRUD operations and uses MongoDB for data persistence.

I am using Mongo Atlas connection string to connect the app to MongoDB and things work fine when I run the application on my local dev machine. But when I push everything to a docker container, in a docker-compose workflow, I start getting this error:

server selection error: server selection timeout, current topology: { Type: ReplicaSetNoPrimary, Servers: [{ Addr: app-test-shard-00-00-zfzs6.mongodb.net:27017, Type: Unknown, State: Connected, Average RTT: 0, Last error: connection() : x509: certificate signed by unknown authority }, { Addr: app-test-shard-00-01-zfzs6.mongodb.net:27017, Type: Unknown, State: Connected, Average RTT: 0, Last error: connection() : x509: certificate signed by unknown authority }, { Addr: app-test-shard-00-02-zfzs6.mongodb.net:27017, Type: Unknown, State: Connected, Average RTT: 0, Last error: connection() : x509: certificate signed by unknown authority }, ] }

This is how my docker-compose.yml looks:

services: 
redis:
    image: redis
    restart: always
app:
    image: docker.pkg.github.com/<user>/<project>/<image>:latest
    ports: 
        - 80:8080
    environment: 
        - APP_ENV=docker
        - GIN_MODE=release
    depends_on: 
        - redis
    restart: on-failure

This is how my connection string looks:
mongodb://user:[email protected]:27017,app-test-shard-00-01-zfzs6.mongodb.net:27017,app-test-shard-00-02-zfzs6.mongodb.net:27017/test?ssl=true&replicaSet=app-test-shard-0&authSource=admin&retryWrites=true&w=majority

I have checked this question and a couple of others, but none seem to fix this.

I also checked docker’s networking config, I am using a bridge driver, which should allow access to outside apps (i.e. Mongo Atlas)

Go Version: 1.13

Mongo Driver: mongodb/mongo-go-driver v1.2.0

Dockerfile:

FROM golang:alpine as builder
WORKDIR /build
COPY . .
RUN apk add git openssh build-base
RUN git config --global url."[email protected]:".insteadOf "https://github.com/"
COPY keys/id_rsa /root/.ssh/id_rsa
RUN chmod 600 /root/.ssh/id_rsa
RUN ssh-keyscan -t rsa github.com >> /root/.ssh/known_hosts
ENV GOPRIVATE=github.com/contributor-org
RUN go build

FROM alpine
WORKDIR /org
COPY --from=builder /build/app .
COPY config/*.yml config/
RUN mkdir -p /var/log
CMD ["./app"]

DB Connection code:

type databaseClient struct { // Implements the Database interface
    collection *mongo.Collection
}

func GetNewClient(cfg *config.Config, log *logger.Logger) (Database, error) {
    clientOptions := options.Client().ApplyURI(cfg.Database.ConnectionString)
    client, err := mongo.NewClient(clientOptions)
    if err != nil {
        log.Errorln(err)
    }
    err = client.Connect(context.Background())

    if err != nil {
        log.Fatalln("Failed to connect to Mongo!", err)
        return nil, err
    }

    log.Info("Connected to Mongo!")

    db := client.Database(cfg.Database.Database)
    if db == nil {
        err := fmt.Errorf("DB (%s) not found", cfg.Database)
        log.Error(err)
        return nil, err
    }
    collection := db.Collection(cfg.Database.Collection)
    if collection == nil {
        err := fmt.Errorf("Collection (%s) not found on DB (%s)", cfg.Database.Collection, cfg.Database.Database)
        log.Error(err)
        return nil, err
    }
    return &databaseClient{collection: collection}, nil
}

DB Interface:

type Database interface {
    GetByBookname(context.Context, string) (*model.Book, error)
    GetOneByFilter(context.Context, map[string]interface{}) (*model.Book, error)
    GetAll(context.Context) ([]*model.Book, error)
    GetAllByFilters(context.Context, map[string]interface{}) ([]*model.Book, error)
    AddBook(context.Context, *model.Book) (string, error)
    UpdateBook(context.Context, string, map[string]interface{}) (*model.Book, error)
    DeactivateBook(context.Context, string) error
    OverwriteBook(context.Context, string, *model.Book) (*model.Book, error)
    OnboardBook(*model.Book, string, bool) (string, error)
}

2

Answers


  1. The problem seems related to the certificate validation.
    You have two options:
    – add the self signed certificate to the CA.
    – skip the validation.

    If you want to skip the self signed certificate validation, you have to modify the ClientOptions struct setting to true the ClientOptions.SSLInsecure variable.

    Login or Signup to reply.
  2. I quick-fixed this by adding &tlsInsecure=true to the MongoDB URI. Still looking for the correct way to fix it though.

    Edit:

    Solved it too adding ca-certificates to the Docker image:

    # Builder step...
    
    FROM alpine:3
    RUN apk update 
        && apk upgrade 
        && apk add --no-cache 
        ca-certificates 
        && update-ca-certificates 2>/dev/null || true
    COPY --from=builder /build/main ./
    CMD ["/main"]
    

    Another option for a smaller image:

    # Builder step...
    
    FROM alpine:3 as certs
    RUN apk --no-cache add ca-certificates
    
    FROM scratch as app
    COPY --from=builder /build/main ./
    COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
    ENTRYPOINT ["/main"]
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search