Kubernetes Tip: How to refer one environment variable in another environment variable declaration?

In Kubernetes, one way to pass configurable data to containers is using environment variable. Below is a pod definition that uses two environment variables.

apiVersion: v1
kind: Pod
metadata:
  name: api
spec:
  containers:
    - image: com.shekhargulati/api
      name: api
      env:
        - name: DATABASE_NAME
          value: "mydb"
        - name: DATASOURCE_URL
          value: jdbc:mysql://mysql:3306/mydb      
      ports:
        - containerPort: 8080

As you can see in the above Pod definition, we are using database name mydb twice. Isn’t it will be awesome if we can use DATABASE_NAME in the DATASOURCE_URL?

Kubernetes supports this use case by providing $(VAR) syntax as shown below.

apiVersion: v1
kind: Pod
metadata:
  name: api
spec:
  containers:
    - image: com.shekhargulati/api
      name: api
      env:
        - name: DATABASE_NAME
          value: "mydb"
        - name: DATASOURCE_URL
          value: "jdbc:mysql://mysql:3306/$(DATABASE_NAME)"
      ports:
        - containerPort: 8080

The Ultimate Dockerfile for Spring Boot Maven and Gradle applications

For Maven users, the ultimate Dockerfile is below.

FROM openjdk:8-jdk-alpine as build
WORKDIR /workspace/app

COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
RUN ./mvnw dependency:go-offline

COPY src src
RUN ./mvnw package -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)

FROM openjdk:8-jre-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","FULL_NAME_OF_SPRING_BOOT_MAIN_CLASS"]

Please make sure to update FULL_NAME_OF_SPRING_BOOT_MAIN_CLASS with Spring Boot application main class.

For Gradle users, the ultimate Dockerfile is below.

FROM openjdk:8-jdk-alpine as build
WORKDIR /workspace/app

COPY gradlew .
COPY gradle gradle
COPY build.gradle .
RUN ./gradlew dependencies

COPY src src
RUN ./gradlew build unpack -x test
RUN mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*.jar)

FROM openjdk:8-jre-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/build/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","FULL_NAME_OF_SPRING_BOOT_MAIN_CLASS"]

Please make sure to update FULL_NAME_OF_SPRING_BOOT_MAIN_CLASS with Spring Boot application main class.

You can watch this video to learn more about optimizing docker images for Spring Boot applications.

Solution: ORA-12514, TNS:listener does not currently know of service requested in connect descriptor

Today, one of the teams was facing the issue ORA-12514, TNS:listener does not currently know of service requested in connect descriptor. They were trying to connect to Oracle using Spring Boot JPA application and getting the exception at application boot up.

Team was able to successfully connect to Oracle using SQLDeveloper. But, when connecting to Oracle using Spring Boot JPA application it was failing to boot up.

Like most developers, we googled around to find the answers. The popular answer that you will get is as mentioned in this stackoverflow question. The answer suggests that you have to update tnsnames.ora file and add your service to it.

I knew it is not the right answer as we are able to connect using SQL Developer.

So, I started looking into the Spring Data JPA configuration of the application. The configuration that was giving error is shown below.

spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@//myhost:1521/efsdev
spring.datasource.username=myuser
spring.datasource.password=mypassword
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect

In the above configuration, there is only one configuration property that could be possibly wrong — spring.datasource.url.

So, I googled around to find the correct way to specify JDBC url for Oracle.

I learned that there are two ways you can specify JDBC string URL. The two ways are:

1) jdbc:oracle:thin:@[HOST][:PORT]:SID

2) jdbc:oracle:thin:@//[HOST][:PORT]/SERVICE

As you can see above, we are using the second way to specify the URL. According to second URL syntax, efsdev is the service name.

Developers mentioned that efsdev is the SID. So, we need to use the first URL.

After changing the configuration to the one mentioned below, application was successfully able to connect with Oracle.

spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@myhost:1521:efsdev
spring.datasource.username=myuser
spring.datasource.password=mypassword
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect

That’s it for this post. I hope this saves someone’s day.

Issue #23: 10 Reads, A Handcrafted Weekly Newsletter For Software Developers

The time to read this newsletter is 165 minutes.

If we encounter a man of rare intellect, we should ask him what books he reads. – Ralph Waldo Emerson

Continue reading “Issue #23: 10 Reads, A Handcrafted Weekly Newsletter For Software Developers”

Enabling Https for local Spring Boot development with mkcert

Today, I discovered mkcert – a tool that generates valid TLS certificate. It works for any hostname or IP, including localhost. In this post, I will show you how to generate a valid PKCS12 format certificate using mkcert. Then, we will use that certificate in a Spring boot application.

We will start by installing mkcert on our local machine. If you are using Mac then we can use brew package manager. For installation instructions specific to your OS you can refer to the documentation.

brew install mkcert

Once mkcert is installed, you can use its CLI to create and install a CA. To do that, run the following command.

mkcert -install

Continue reading “Enabling Https for local Spring Boot development with mkcert”

Dockerizing a Vue.js application

It is common these days to run front-end and back-end services inside Docker containers. The front-end service usually talks using a API with the back-end service.

In this post we will cover following:

  1. Setting up a Docker based development environment with hot reloading
  2. Building a production ready Docker image with API url passed using environment variable

Continue reading “Dockerizing a Vue.js application”

Running Tests and Building React applications with Gradle Build Tool

In this short post, I will show you how you can integrate React applications created using create-react-app with Gradle build tool. We will cover how to build and run the tests as part of the Gradle build.

Continue reading “Running Tests and Building React applications with Gradle Build Tool”

A simple introduction to distributed systems

A couple of weeks back a junior developer asked me a seemingly simple question – What is a distributed system? One question led to another and we end up spending more than an hour discussing different aspects of distributed systems. I felt my knowledge on distributed systems was rusty and I was unable to explain concepts in a simple and clear manner.

In the last two weeks since our discussion I spent time reading distributed systems literature to gain better understanding of the basics. In a series of post starting today, I will cover distributed system basics. In today’s post we will cover what and why of distributed systems.

Continue reading “A simple introduction to distributed systems”

Issue #22: 10 Reads, A Handcrafted Weekly Newsletter For Humans

The time to read this newsletter is 150 minutes.

Curiosity is, in great and generous minds, the first passion and the last – Samuel Johnson

  1. Monorepos: Please don’t!: 20 mins read. In this post, Matt Klein gives reasons to why monorepo approach does not provide benefits most often cited by monorepo proponents. His recommendation is to go with polyrepo structure. The post makes four valid arguments:
    1. Organizations that use monorepo spend considerable engineering resources on building tools to work with monorepos. Most organisations don’t have such luxury.
    2. Monorepo makes it difficult to open source internal projects as you have single commit history
    3. Most VCS are not meant to be used for large monolithic repositories. There is some work done by Microsoft as part of its git VFS project but it has some rough edges.
    4. The last interesting point that post makes is The frank reality is that, at scale, how well an organization does with code sharing, collaboration, tight coupling, etc. is a direct result of engineering culture and leadership, and has nothing to do with whether a monorepo or a polyrepo is used.

    The main drawback of polyrepo approach is that it creates a culture where different teams own different parts of the code. There are few people in organization aware of the big picture. This point is beautifully put by Adam Jacob in his post – Monorepo: please do!.

    My take on this is somewhere in between. For example, if you are building a web application then I like to keep all backend Microservices in one repository and front-end application in another repo. I think the best is somewhere in between the both approaches. Taking either too far does not work.
    Continue reading “Issue #22: 10 Reads, A Handcrafted Weekly Newsletter For Humans”