Pass URL from K8s-ConfigMap to SpringBoot Application - spring-boot

I'm quite new to Kubernetes and started using MiniKube to experiment with K8s.
Explanation
This is the (very simple) scenario I want to realize:
PrintClient provides a http-endpoint: <url>/<stringToPrint>
PrintClient redirects <stringToPrint> to PrintServer
PrintServer just print out <stringToPrint> in console
The scenario is meant as a proof-of-concept, and will be the basis for a evaluation in the company I'm working at, therefore it needs to accomplish the following tasks:
both applications are running inside the MiniKube-cluster
PrintClient should have an ExternalService
PrintServer should have an InternalService
the URL for PrintServer should come from a ConfigMap using
PrintServer's InternalService
Code
Here are the relevant files for my scenario.
At first I show you the code of both applications:
PrintClient
PrintClientApplication.java
#SpringBootApplication
public class PrintClientApplication {
public static void main(String[] args) {
SpringApplication.run(PrintClientApplication.class, args);
}
#Bean
public RestTemplate getRestTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
Api.java
#RestController
public class Api {
#Autowired
private RestTemplate rs;
#Value("${PRINT_SERVER_URL}")
private String printServerUrl;
#GetMapping("/{string}")
public void print(#PathVariable("string")String string) {
System.out.println(printServerUrl);
rs.getForObject( printServerUrl + string, String.class);
}
}
application.properties
PRINT_SERVER_URL=thisIsJustAPlaceholder
Dockerfile
FROM java:8-jdk-alpine
COPY /target/print_client-0.0.1-SNAPSHOT.jar /usr/app/
ENV PRINT_SERVER_URL=blah
WORKDIR /usr/app/
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "print_client-0.0.1-SNAPSHOT.jar", "PRINT_SERVER_URL=${PRINT_SERVER_URL}"]
deployment+service
apiVersion: apps/v1
kind: Deployment
metadata:
name: print-client-deployment
spec:
selector:
matchLabels:
app: print-client-label
replicas: 1
template:
metadata:
labels:
app: print-client-label
spec:
containers:
- name: print-client
image: patrickshaikh/print_client:1
ports:
- containerPort: 8080
env:
- name: PRINT_SERVER_URL
valueFrom:
configMapKeyRef:
name: print-client-configmap
key: print_server_url
---
apiVersion: v1
kind: Service
metadata:
name: print-client-service
spec:
selector:
app: print-client-label
type: LoadBalancer
ports:
- protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30001
configmap
apiVersion: v1
kind: ConfigMap
metadata:
name: print-client-configmap
data:
print_server_url: print-server-service
PrintServer
Api.java
#RestController
public class Api {
#GetMapping("/{string}")
public void hello(#PathVariable("string") String string) {
System.out.println(string);
}
}
deployment+service
apiVersion: apps/v1
kind: Deployment
metadata:
name: print-server-deployment
spec:
selector:
matchLabels:
app: print-server
replicas: 1
template:
metadata:
labels:
app: print-server
spec:
containers:
- name: print-server
image: patrickshaikh/print_server:1
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: print-server-service
spec:
selector:
app: print-server
type: LoadBalancer
ports:
- protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30000
(It is an ExternalService for testing purpose, but will be internal later.)
I already checked if CoreDNS is running:
Misbehaviour
I used the name of the print-server-service in the ConfigMap but instead of resolving it to an URL before passing the value to the container on initialization, it treats it as a string (during a testiteration I printed the URL to console as well).
Using the IP of PrintServers InternalService results in a 404 while using the IP of its ExternalService works flawlessly.
Questions at answerers
Why can't it resolve the reference to the print-server-service to
its internal IP?
What would be the proper way of passing URLs to a container using
servicenames?
Is there anything else in terms of "best practice" in my scenario i
could adapt?
Thanks in advance

Related

Springboot docker-compose redis Cannot get Jedis connection;

This may seems as duplicate of docker-compose with springboot and redis and docker-compose redis connection issue but the solutions proposed there are not working in my case.
I am using springboot and the other services are unable to connect to redis service.
Below is my docker compose file:
version: "3.7"
services:
...
users:
build: ./users
ports:
- "8081:8081"
networks:
- jiji-microservices-network
depends_on:
- registry
- gateway
- redis_cache
- postgresDB
- rabbitmq
links:
- redis_cache
- postgresDB
- rabbitmq
environment:
# SPRING_CACHE_TYPE: redis
# SPRING_REDIS_HOST: redis_cache
# SPRING_REDIS_PORT: 6379
# SPRING_REDIS_PASSWORD:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgresDB:5432/jiji_users
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: postgres
SPRING_JPA_HIBERNATE_DDL_AUTO: update
EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://registry:8090/eureka
postgresDB:
image: postgres
restart: unless-stopped
ports:
- "5432:5432"
networks:
- jiji-microservices-network
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: jiji_users
redis_cache:
image: redis:latest
restart: on-failure
command: ["redis-server","--bind","redis_cache","--port","6379"]
ports:
- "6379:6379"
networks:
- jiji-microservices-network
rabbitmq:
image: rabbitmq:management
ports:
- "5672:5672"
- "15672:15672"
networks:
- jiji-microservices-network
networks:
jiji-microservices-network:
driver: bridge
Here below is my application.yml file:
...
cache:
type: redis
redis:
host: redis_cache
port: 6379
# cache-null-values: true
time-to-live: 2592000 #30 days
...
The error message I am getting:
users_1 | 2022-03-28 02:53:40.417 INFO 1 --- [nio-8081-exec-4] c.o.u.s.CustomAuthorizationFilter : /api/v1/users/getCode
users_1 | Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
docker ps shows that all the containers are up and running and that redis is listening on port 6379.
PS: It works fine without docker.
The issue was related to my Redisconfiguration. Fixed bit adding redis host and redis port to JedisConnectionFactory Bean.
#Configuration
#Slf4j
public class RedisConfiguration {
#Value("${spring.redis.host}")
private String REDIS_HOST;
#Value("${spring.redis.port}")
private Integer REDIS_PORT;
#Bean
public JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(REDIS_HOST, REDIS_PORT);
return new JedisConnectionFactory(config);
}
#Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setEnableTransactionSupport(true);
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
}

Spring Config Server : get secrets from vault with specific path

I am trying to get my microservices configuration from a config server connected to 2 sources : git and vault (for secrets). I have the config bellow:
in the config-server:
server:
port: 8888
spring:
profiles:
active: git, vault
cloud:
config:
server:
vault:
port: 8200
host: 127.0.0.1
kvVersion: 2
git:
order: 2
uri: git#gitlab.git
and in the client side in the bootstrap.yml:
spring:
application:
name: my-service-name
cloud:
config:
uri: http://localhost:8888
token: //token
label: dev
But in my vault i have the path like this :
secret/cad
|--my-service-name
When i make my secret directly in /secret/my-service-name i can access my secrets, but how can i configure acces to secrets in : /secret/cad/my-service-name
Thank you.
You can create your Custom configuration Class that implements VaultConfigurer where you can override to your custom path
#Configuration
Public class CustomVaultConfiguraton implements VaultConfigurer {
#override
public void addSecretsBackends(SecretBackendConfigurer configures){
configures.add("customPath");
}
}
add above configuration class in spring.factories
org.springframework.cloud.bootstrap.BootstrapConfiguration=\packagename.CustomVaultConfiguration

Spring Cloud kubernetes not loading config map

I have created the 2 config map named personservice and personservice-dev.
I am running spring boot application with profile dev but it is not loading the right config map. This is what I see in logs of the pod which gets crashed.
2019-11-05 16:29:37.336 INFO [personservice,,,] 7 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource {name='composite-configmap', propertySources=[ConfigMapPropertySource {name='configmap.personservice.default'}]}
2019-11-05 16:29:37.341 INFO [personservice,,,] 7 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: SecretsPropertySource {name='secrets.personservice.default'}
2019-11-05 16:29:37.445 INFO [personservice,,,] 7 --- [ main] c.person.PersonMicroServiceApplication : The following profiles are active: kubernetes,dev
Kubectl get configmaps
Deployment file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: personservice
labels:
app: personservice
spec:
replicas: 1
selector:
matchLabels:
app: personservice
template:
metadata:
labels:
app: personservice
spec:
containers:
- name: personservice
image: microservice-k8s/personmicroservice-k8s:1.0
ports:
- containerPort: 8080
env:
- name: PROFILE
value: "dev"
- name: SERVER_PORT
value: "8080"
- name: ZIPKIN_URI
value: "http://172.19.27.145:9411"
Bootstrap:
spring:
application:
name: personservice
You confused things. Your configmap is named personservice-dev and your application's name is personservice not personservice-dev, by default Spring Cloud K8S looks for configmap with name equals to spring.application.name and not spring.application.name-{profile}.
You have 2 ways to solve your problem:
1-Remove personservice-dev and in your personservice configmap:
kind: ConfigMap
apiVersion: v1
metadata:
name: personservice
data:
application.yml: |-
p1:
pa: blabla
---
spring:
profiles: dev
p1:
pa: blibli
---
spring:
profiles: prod
p1:
pa: blublu
2-Keep personservice-dev and personservice and define this in bootstrap.yml:
spring:
cloud:
kubernetes:
config:
name: ${spring.application.name} #This is optional
sources:
- name: ${spring.application.name}-${PROFILE} # Here you get your `personservice-dev` configmap

Redis & Spring Boot integration with K8S error

I have the following docker file:
FROM openjdk:8-jdk-alpine
ENV PORT 8094
EXPOSE 8094
RUN mkdir -p /app/
COPY build/libs/fqdn-cache-service.jar /app/fqdn-cache-service.jar
WORKDIR /build
ENTRYPOINT [ "sh" "-c", "java -jar /app/fqdn-cache-service.jar" ]
docker-compose.yaml file:
version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
image: fqdn-cache-service
ports:
- "8094:8094"
links:
- "db:redis"
db:
image: "redis:alpine"
#hostname: redis
ports:
- "6378:6378"
deployment.yaml file
apiVersion: apps/v1
kind: Deployment
metadata:
name: fqdn-cache-service
spec:
selector:
matchLabels:
run: spike
replicas: 1
template:
metadata:
labels:
app: redis
run: spike
spec:
containers:
- name: fqdn-cache-service
imagePullPolicy: Never
image: fqdn-cache-service:latest
ports:
- containerPort: 8094
protocol: TCP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
selector:
matchLabels:
run: spike
replicas: 1
template:
metadata:
labels:
run: spike
spec:
hostname: redis
containers:
- name: redis
image: redis:alpine
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: fqdn-cache-service
labels:
run: spike
spec:
type: NodePort
ports:
- port: 8094
nodePort: 30001
selector:
run: spike
---
apiVersion: v1
kind: Service
metadata:
name: redis
labels:
run: spike
app: redis
spec:
type: NodePort
ports:
- port: 6379
nodePort: 30002
selector:
run: spike
And the cluster info ip is 127.0.0.1.
I'm using microk8s over ubuntu OS.
If I request for get by and ID (127.0.0.1/webapi/users/1) I get the error:
Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
Although on regular java application with redis or dockerize spring boot with redis it's working.
Any help why this is happened?
This is the configuration of the spring boot:
#Configuration
public class ApplicationConfig {
#Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName("127.0.0.1");
factory.setPort(30001);
factory.setUsePool(true);
return factory;
}
#Bean
RedisTemplate redisTemplate() {
RedisTemplate<String, FqdnMapping> redisTemplate = new RedisTemplate<String, FqdnMapping>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
return redisTemplate;
}
}
The issue also happenes if the host name is localhost and\or the port is 6379...
Thanks!
When you're running in a container, 127.0.0.1 usually refers to the container itself, not to the host the container is running on. If you're trying to connect to a service, try using its name and port: "redis" on port 6379 and "fqdn-cache-service" on 8094.

virtualHost Not Creating on RabbitMQ server using application.yml springboot and from config server

Virtualhost are not getting created on RabbitMQ server based on configuration
Do i have make sure VH aka Virtual Hosts on RabbitMQ .
Am i missing some configuration.
Please find the configuration below
application.yml
spring:
rabbitmq:
host: 127.0.0.1
virtual-host: /defaultVH
username: defaultUser
password: defaultPassword
cloud:
stream:
bindings:
saviyntSampleQueueA:
binder: rabbit-A
contentType: application/x-java-object
group: groupA
destination: saviyntSampleQueueA
saviyntSampleQueueB:
binder: rabbit-B
contentType: application/x-java-object
group: groupB
destination: saviyntSampleQueueB
binders:
rabbit-A:
defaultCandidate: false
inheritEnvironment: false
type: rabbit
environment:
spring:
rabbitmq:
host: 127.0.0.1
virtualHost: /vhA
username: userA
password: paswdA
port: 5672
connection-timeout: 10000
rabbit-B:
defaultCandidate: false
inheritEnvironment: false
type: rabbit
environment:
spring:
rabbitmq:
host: 127.0.0.1
virtualHost: /vhB
username: userB
password: paswdB
port: 5672
connection-timeout: 10000
bootstrap.yml
############################################
# default settings
############################################
spring:
main:
banner-mode: "off"
application:
name: demo-service
cloud:
config:
enabled: true #change this to use config-service
retry:
maxAttempts: 3
discovery:
enabled: false
fail-fast: true
override-system-properties: false
server:
port: 8080
Added default spring boot added Enable binding
#EnableBinding({MessageChannels.class})
#SpringBootApplication
public class Configissue1124Application {
public static void main(String[] args) {
SpringApplication.run(Configissue1124Application.class, args);
}
}
Now simple straightforward massage channel to to dispatch massage
interface MessageChannels {
#Input("saviyntSampleQueueA")
SubscribableChannel queueA();
#Input("saviyntSampleQueueB")
SubscribableChannel queueB();
}
When i ran the Boot Application its not creating any Virtualhost on the system . i tried using config server buy providing same configuration but still no luck
can you please find if some thing am missing.
Thanks in Advance
The AMQP protocol (or RabbitMQ REST API) provides no mechanism to provision virtual hosts from the client.
Virtual hosts must be provisioned manually on the server.

Resources