How to get docker-compose container to see Redis host? - go

I have this simple docker-compose.yml file:
version: '3.8'
services:
bot:
build:
dockerfile: Dockerfile
context: .
links:
- redis
depends_on:
- redis
redis:
image: redis:7.0.0-alpine
ports:
- "6379:6379"
environment:
- REDIS_REPLICATION_MODE=master
restart: always
volumes:
- cache:/data
command: redis-server
volumes:
cache:
driver: local
This is how the bot (in Go) connects to redis:
import "github.com/go-redis/redis/v8"
func setRedisClient() {
rdb = redis.NewClient(&redis.Options{
Addr: "redis:6379",
Password: "",
DB: 0,
})
}
bot Dockerfile:
FROM golang:1.18.3-alpine3.16
WORKDIR /go/src/bot-go
COPY . .
RUN go build .
RUN ./bot-go
But when I run docker-compose up --build I always get:
panic: dial tcp: lookup redis on 192.168.65.5:53: no such host
redis host is never seen no matter what changes I make to the host or to docker-compose file.
The app does work without Docker when I configure the client to local.
What I am doing wrong exactly?

The problem is the bot-go image never stops building. Change RUN ./bot-go to CMD [ "./bot-go" ] in the Dockerfile and everything will work fine.

Related

Calling backend docker container from frontend + client side vs server side rendering

I'm currently working on a full stack application using Spring-boot (Kotlin), SvelteKit (run with Vite), and MongoDB, each with their own Docker container. My backend service is being forwarded to port 6868 on my localhost, and when I run my frontend service with "npm run dev" locally (which triggers this script): vite dev --host 0.0.0.0 --port 8080 and remove the service from my docker-compose.yml (see frontend-svelte service in docker-compose below), I am able to call my backend at localhost:6868 (see +page.js below). However, when I run my frontend inside of a docker container, the request to localhost:6868 fails. This sort of makes sense to me since localhost:6868 would refer to the inside of the docker container if the code was being sent from the server (docker container) as opposed to the browser. When I change localhost:6868 to spring-boot:8080 (the docker container) the initial request sent Server side does succeed (i.e. the console log below in /frontend-svelte/routes/+page.js does print out) however, there is still an error in the browser for the subsequent requests being sent from the client side. It seems to me that the issue is the discrepancy caused by requests sent from client-side vs server-side, so how can I resolve this issue? Thanks everyone for your help!
docker-compose.yml
version: "3.8"
services:
mongodb:
image: mongo:5.0.2
restart: unless-stopped
ports:
- 27017:27017
volumes:
- db:/data/db
spring-boot:
image: bracket_backend
build:
context: ./backend
dockerfile: Dev.Dockerfile
depends_on:
- mongodb
ports:
- 6868:8080
stdin_open: true
tty: true
volumes:
- ./backend/src:/app/src
env_file:
- ./.env
frontend-svelte:
image: bracket_frontend
build:
context: ./frontend-svelte
dockerfile: Dev.Dockerfile
ports:
- 1234:8080
stdin_open: true
tty: true
volumes:
- ./frontend-svelte/src:/app/src
depends_on:
- spring-boot
volumes:
db:
/backend/Dev.Dockerfile
FROM maven:3.8.6-openjdk-18-slim
WORKDIR /app
COPY ./.mvn ./mvn
COPY ./mvnw ./
COPY ./pomDev.xml ./
# Note that src is mounted as a volume to allow code update w/o restarting container
ENTRYPOINT mvn spring-boot:run -f pomDev.xml
/frontend-svelte/Dev.Dockerfile
FROM node:16-slim
WORKDIR /app
COPY package.json .
RUN npm install --legacy-peer-deps
COPY svelte.config.js .
COPY vite.config.js .
COPY jsconfig.json .
COPY playwright.config.js .
# Note that src is mounted so changes will occur.
ENTRYPOINT npm run dev
/frontend-svelte/routes/+page.js (this is where the request to the backend is made. This succeeds if not run from docker container)
import { getBaseUrl } from '$lib/utils.js';
/** #type {import('./$types').PageLoad} */
export async function load({ params }) {
console.log("test")
const response = await fetch(`http://localhost:6868/api/groups`); // THIS LINE MAKES THE REQUEST TO THE BACKEND
console.log("respoonse is: ");
console.log(response);
if (!response.ok) {
throw new Error(`Error! status: ${response.status}`);
}
return response.json()
}

How to get hostname from one container to another using docker compose?

I have two docker containers. One backend, and the other db (postgres). They both are linked. How do I utilise the backend environment HOST variable in the golang docker container?
From my understanding, both containers have their own IP addresses. I cannot use 'localhost' in the golang container because postgres isn't on localhost, but in an isolated container.
version: "3.7"
services:
backend:
image: golang:1.16
build: ./
working_dir: /app
volumes:
- ./backend/:/app
environment:
HOST: db
command: go run main.go
ports:
- 8080:8080
depends_on:
- db
db:
image: postgres
restart: always
environment:
POSTGRES_USER: gorm
POSTGRES_PASSWORD: gorm
POSTGRES_DB: gorm
ports:
- 9920:9920
I've tried researching how to access this variable as well as check Docker tutorials/documentation, but haven't found a solution.
Docker compose does DNS resolution. You should be able to access your database by name.
Remove:
environment:
HOST: db
Correct the postgres port to 5432:
db:
...
ports:
- 5432:5432
You must be able to connect like so:
db := pg.Connect(&pg.Options{
Addr: "db:5432",
User: "gorm",
Database: "gorm",
Password: "gorm",
})
As for environment variables, you can declare and access them like this:
backend:
environment:
POSTGRES_USER: gorm
...
os.Getenv("POSTGRES_USER")
Docker compose will create a network for your containers where they can communicate and reach each other.
You can make a simple change to your docker compose file by adding a name to your services which will make sure they get the same name each time.
version: "3.7"
services:
backend:
image: golang:1.16
build: ./
container_name: backend
working_dir: /app
volumes:
- ./backend/:/app
command: go run main.go
ports:
- "8080:8080"
depends_on:
- db
db:
image: postgres
restart: always
container_name: db
environment:
POSTGRES_USER: gorm
POSTGRES_PASSWORD: gorm
POSTGRES_DB: gorm
ports:
- "9920:5432"
The default port for Postgres is 5432, so I mapped it to your 9920. Then, you can access the db container from the backend container by specifying:
db:9920

Connect service container to db container

I'm new to docker and started to play with it on my small project.
I have dockerized the service itself with the following Docker file:
ROM adoptopenjdk:11-jdk-hotspot AS DEPENDENCIES_BUILD_IMAGE
ENV APP_HOME=/usr/app/
WORKDIR $APP_HOME
COPY build.gradle settings.gradle gradlew $APP_HOME
COPY gradle $APP_HOME/gradle
RUN ./gradlew build || return 0
COPY . .
RUN ./gradlew build
FROM adoptopenjdk/openjdk11:jdk-11.0.7_10-alpine AS FINAL
ENV JAR_TEMPLATE=myapp-0.0.1-SNAPSHOT.jar
ENV ARTIFACT_NAME=myapp.jar
ENV APP_HOME=/usr/app
WORKDIR $APP_HOME
COPY --from=DEPENDENCIES_BUILD_IMAGE $APP_HOME/build/libs/$JAR_TEMPLATE .
RUN mv $JAR_TEMPLATE $ARTIFACT_NAME
EXPOSE 8080
CMD ["java", "-jar", "budget-calculator.jar"]
Side note - I know that there's a problem that I'm always copying 0.0.1-SNAPSHOT - but I'm not sure how to solve it at the moment.
After that I wanted to connect my service to a Postgres DB with docker-compose using this confirmation:
version: '3'
services:
backend:
build: .
container_name: myapp
ports:
- "8080:8080"
links:
- "db"
depends_on:
- db
networks:
- backend
db:
restart: unless-stopped
image: postgres:10
container_name: myapp-db
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=myapp
ports:
- 5436:5436
networks:
- backend
networks:
backend:
After that I've updated my application.properties file to indicate that the DB link is on the other container as follow:
spring.flyway.url=jdbc:postgresql://db:5436/myapp
spring.flyway.user=postgres
spring.flyway.password=secret
spring.flyway.baseline-on-migrate=true
spring.datasource.url=jdbc:postgresql://db:5436/myapp
spring.datasource.username=postgres
spring.datasource.password=secret
spring.datasource.driverClassName=org.postgresql.Driver
Now I had 2 problems:
While I assumed that build: . will rebuild my image every time
that I'm running docker-compose up if something changed in
practice I saw that it's not the case.
When the backend service starts flyway (a migration DB library) try
to connect to the database and cannot resolve the connection.
I've seen online that the usage of - links is deprecated and I should use the networks but both do not seem to work - what am I missing?
There are 2 problems with my configurations, the first one - the internal port of Postgres was configured as 5436 while the default port of the image is 5432 (I've updated both of them to 5432)
the second one, in order to pass the IP of the DB to the service I've added the following environment variables to the service image:
environment: # Pass environment variables to the service
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/budget
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: secret
SPRING_FLYWAY_URL: jdbc:postgresql://db:5432/budget
SPRING_FLYWAY_USER: postgres
SPRING_FLYWAY_PASSWORD: secret
So my current working configuration is this:
version: '3.8'
services:
backend:
build: .
container_name: app-service
ports:
- "8080:8080"
depends_on:
- db
environment: # Pass environment variables to the service
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/myapp
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: secret
SPRING_FLYWAY_URL: jdbc:postgresql://db:5432/myapp
SPRING_FLYWAY_USER: postgres
SPRING_FLYWAY_PASSWORD: secret
db:
restart: unless-stopped
image: postgres:10
environment:
- POSTGRES_DB=myapp
- POSTGRES_PASSWORD=postgres
- POSTGRES_USER=secret
volumes:
- myapp_data:/var/lib/postgresql/data
ports:
- 5432:5432
volumes:
myapp_data:

Spring boot + docker + rest template connection refused

I have two services, spring boot docker and when I try communication with rest template I got java.net.ConnectException: Connection refused (Connection refused)
url is http://localhost:8081/api/v1/package/250Mbps
Service 1 docker-compose.yml:
product_catalogue_service:
image: openjdk:8-jdk-alpine
ports:
- "8081:8081"
volumes:
- .:/app
working_dir: /app
command: ./gradlew bootRun
restart: on-failure
Service 2 docker-compose.yml:
order_service:
image: openjdk:8-jdk-alpine
ports:
- "8083:8083"
volumes:
- .:/app
working_dir: /app
command: ./gradlew bootRun
restart: on-failure
Rest template URL, and it is working when I run project 2 from the IntelliJ:
http://localhost:8081/api/v1/package/250Mbps
When I run docker ps, name of first service is:
productcatalogueservice_product_catalogue_service_1
I tried to use that instead of localhost - unknown host exception.
I tried "product_catalogue_service_1" instead, also unknown host exception,
and finally I tried "product_catalogue_service" also unknown host exception.
Any idea?
By default, docker-compose creates a network between your containters and assign the serivce name as de host name.
So, you can reach the product_catalog_service from order_service like so: http://product_catalog_service:8081/api/v1/package/250Mbps
Now, from your post it seems that you have two different docker-compose.yml files, one for each service. In this case, each container is living in its own network (created by docker-compose) and they can't see each other, at least by default.
Honestly, I've never try to connect two containers created from two different docker-compose files. I always create one docker-compose.yml file, put there all my services and let docker-compose manage the network between them.
Using one docker-compose.yml
version: ...
services:
product_catalogue_service:
image: openjdk:8-jdk-alpine
ports:
- "8081:8081"
volumes:
- .:/app
working_dir: /app
command: ./gradlew bootRun
restart: on-failure
order_service:
image: openjdk:8-jdk-alpine
ports:
- "8083:8083"
volumes:
- .:/app
working_dir: /app
command: ./gradlew bootRun
restart: on-failure
One last thing, this answer explains in great detail why localhost:8081 is not working from your order_service container.

Can't reach server inside docker container from host

I am hosting a mysql server and a go http server in docker. I am unable to hit the http server from my host machine. My host machine is a mac.
I have tried using localhost:8080 and ipofserver:8080. I get the ip from the docker inspect. I am able to connect to my mysql server from my host, but i can't hit the server from the host.
Here is my docker ps output.
0.0.0.0:8080->8080/tcp
0.0.0.0:3306->3306/tcp, 33060/tcp
Below are my details:
Docker Desktop version 2.0.0.3.
docker-compose
version: '3.1'
services:
mysql:
image: mysql:latest
restart: always
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: mydb
volumes:
- mysql:/var/lib/mysql
ports:
- "3306:3306"
networks:
- mynetwork
server:
image: server:latest
networks:
- mynetwork
ports:
- "8080:8080"
volumes:
mysql: ~
networks:
mynetwork:
driver: "bridge"
mysql dockerfile
FROM mysql:8.0.16
COPY ./scripts/mysql/dbgen-v1.sql /docker-entrypoint-initdb.d/
EXPOSE 3306
server dockerfile
FROM golang:1.12.5
WORKDIR a/go/path
COPY . .
ENV GOBIN=/usr/local/bin
RUN go get github.com/go-sql-driver/mysql
RUN go get github.com/iancoleman/strcase
RUN go get github.com/jmoiron/sqlx
RUN go get github.com/spf13/cobra
RUN go get github.com/gorilla/websocket
RUN go get github.com/spf13/viper
RUN go install -v cmd/project/main.go
EXPOSE 8080
CMD ["main"]
(This answer is based on the chat we had in the comments)
In order to expose the web server from inside the container to the host it needs to bind to 0.0.0.0 and not to 127.0.0.1. Using 0.0.0.0 ensures that the web server binds to the bridge interface that can be accessed from the host side.
Relevant Docker docs: https://docs.docker.com/v17.09/engine/userguide/networking/default_network/binding/

Resources