This content originally appeared on Level Up Coding - Medium and was authored by Colin Bester
As our startup is progressing to a fully fledged company and our client base is growing, it is time to shift from our current script based deployment practices. With this in mind I decided to take a look and see what Kubernetes is all about, which led me to look at using docker as a container.
As I work best with my fingers at the keyboard when researching and evaluating new technologies I decided to create an environment where NGINX, Akka-Http and Redis as my data store are all containerized and communicating with each other in both directions. I thought to add akka-http server sent events to client browser as well as have Redis publish key and event changes to my RESTful akka-http server — my thinking, let’s test the heck out of networking between containers :-).
I have posted two projects to Github which you’re welcome to take a look at and use: akka-http server and docker-compose setup
I decided to start with the easiest component first, and create/setup a Redis container.
Redis Container
There is a lot of information out on the web on setting up and running a Redis container.
In my case I wanted to add the ability for Redis to publish keyspace and event notifications so needed to figure out how to configure Redis’notify-keyspace-events without having to rely on application to perform this action. Turns out that this is easily done via docker-compose supplying redis.conf file.
After creating parent folder dockerized-akka-app I added a redis-config child folder with the following redis.conf file. Note this folder can be pulled from docker-compose setup project.
Then, under the parent folder dockerized-akka-http, created a docker-compose.yml file.
As we proceed through this post we will be building on this file to eventually manage all three of our containers.
Before proceeding you need to create a docker network, this can be accomplished using docker network command:docker network create external-example
Create redis services, binding internal and external volume to allow for external configuration of container.
- volumes instructs container to bind contents found under redis-config folder to docker folder /usr/local/etc/redis
- ports exposes standard redis internal port 6379 to external port 12345. This should not strictly be necessary but is a handy convenience during development cycle.
- command runs redis server passing in location of redis.conf file.
- networks allows for setting up a docker network accessible between the containers in the docker-compose file — more on this later.
Navigate to the parent folder and after ensuring docker is running on your system, execute docker-compose up -d at command prompt to create redis containers.
If you have redis installed locally on your machine you can connect and verify connection using redis-cli -p 12345. If you don’t then you can connect to container and run shell by executing docker exec -it <container-name> sh
To determine container name you can review output from running docker ps which will display container name in the last column — in my case the name shown is akka-app_redis_1.
Once connected to docker container and shell is available you can run redis-cli from within docker container and test — for example:
❯ docker exec -it akka-app_redis_1 sh
/data #redis-cli
127.0.0.1:6379> ping
PONG
You now have succesfully created and deployed a Redis container with external configuration.
Akka-Http Backend Server
Continuing with our quest is to create our Akka-Http RESTful backend service. In this article I won’t be going into creating the scala akka-http project and have taken poetic license on coding standards but wanted to rather focus on specifics for this article. Full and working source code can be found on akka-http server repository.
If you’re interested in understanding more on the EventSource and SSE take a look at medium post.
The scala application serves a basic single VUE page displaying a list of actors deployed, ability to set a key/value pair in Redis and display notified changes received via Redis’ publication feature, and for fun, added a timer tick to send datetime via SSE to frontend. A little overkill for simple example but I was concerned on the networking aspect so wanted to cover my basis in evaluating.
To facilitate providing subscription resource to redis events I decided to go with a Subscriber Actor where in Akka code I could send a subscribe message together with a callback function. For more detail, I would suggest referring to akka-http server project.
Fortunately creating a docker image is relatively simple and I ended up using sbt-native-packager. Following their instructions worked out of the box for me. Below are build.sbt lines relevant to creating docker image.
Note, that in line 12, dockerCommands allows for adding of command lines to Dockerfile. As I was using alpine image to reduce memory footprint, I needed to add bash which was not part of standard image. This allowed me to run a bash shell inside of container for debugging.
On running sbt docker:publishLocal, the necessary images were downloaded, and a Dockerfile was created undertarget folder and an image was created and available.
Now on to the fun part in setting up docker’s networking to allow the akka app to communicate directly to redis.
Time to update the docker-compose.yml file.
I added a new folder under the parent folder and named it akka-config and created logback.xml and application.conf files for configuring the Akka application.
To setup the scala application to access the containerized Redis application, open the docker-compose file and add the new akka-server service to services.
Note that the service names will automatically create network aliases which you will use to configure networking.
In this case create entry in application.conf to configure Redis Url, noting that redis’ service name is the alias used to access Redis from with the Akka container.
redis-server {
uri = "redis://redis:6379"
}
Everything worked pretty smoothly but I did battle with getting my EventSource registration and responses to work correctly. Outside of the docker environment everything worked as expected but the moment I added docker containers I could no longer get it to work with a mix of CORS issues etc.
It took some time looking at Javascript for EventSource until I realized that you can pass options to EventSource when registering to endpoint.
In my setupStream function I had to include object {withCredentials: true}. From Mozilla’s developer site:
The XMLHttpRequest.withCredentials property is a Boolean that indicates whether or not cross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates. Setting withCredentials has no effect on same-site requests.
let evtSource = new EventSource("api/events",
{withCredentials: true})
evtSource.addEventListener('myEvent', event => {
let data = JSON.parse(event.data)
if (data.event === 'date') {
this.now = data.value
this.value = data.value
} else if (data.event="userchange") {
this.username = data.value.name
this.online = data.value.online
}
}, false)
To re-run docker-compose and bring up both Redis and the Akka app navigate back to parent directory and shut down services and then bring them back up using docker-compose down/up.
❯ docker-compose down
Stopping akka-app_akka-server_1 ... done
Stopping akka-app_redis_1 ... done
Removing akka-app_akka-server_1 ... done
Removing akka-app_redis_1 ... done
Network external-example is external, skipping
akka-app on main took 2s
❯ docker-compose up -d
Creating akka-app_redis_1 ... done
Creating akka-app_akka-server_1 ... done
akka-app on main
❯
Pull up your favorite browser (I use Chrome and Brave for development work) and navigate to http://localhost:8082 to view client screen. On startup, the various actor paths will be displayed and SSE will show a waiting status for approximately 5 seconds and then update — see below:
NGINX
Now onto the final segment of our experiment, creating a NGINX service to redirect/proxy calls.
In this Akka example, the VueJs front end application is served by a simplified index.html and myScript.js files. In a real world application, the front end application would be more involved and packaged via vue-cli’s or Vites module bundlers. NGINX is very well suited to serving these files, directing traffic to web pages and restful end points (normally via some api path). For now we are staying with a simple route.
If interest is shown I will publish post on full Vite-vue app communicating via NGINX to backend handling SSL/TLS certificates etc.
Setting up NGINX has gotten so much easier over the years. The biggest issue nowdays is figuring out what you actually want to do with it — the following will also serve as basic template for configuring NGINX.
First navigate to docker-compose parent folder and create two directories nginx-config and Nginx-certs. For now we will leave the certificates directory empty.
In nginx-config we will create our nginx configuration file. As this file references, copy the mime.types file from github and place in folder. Then edit the nginx.conf along the lines of:
Now update the docker-compose file to add NGINX service, noting that NGINX is last service in the list and order is important. If NGINX service is defined before akka-server then docker-compose will complain that network akka-server can not be resolved.
Restarting docker containers:
❯ docker-compose down
Stopping akka-app_akka-server_1 ... done
Stopping akka-app_redis_1 ... done
Removing akka-app_akka-server_1 ... done
Removing akka-app_redis_1 ... done
Network external-example is external, skipping
akka-app on main took 2s
❯ docker-compose up -d
Creating reverse ... done
Creating akka-app_redis_1 ... done
Creating akka-app_akka-server_1 ... done
akka-app on main
❯
I did experience caching issues after adding nginx and restarting services, simple clearing of browser cache and navigating to http://localhost worked!
Dockerizing Scala/Redis/NGINX was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding - Medium and was authored by Colin Bester
Colin Bester | Sciencx (2021-03-10T13:58:24+00:00) Dockerizing Scala/Redis/NGINX. Retrieved from https://www.scien.cx/2021/03/10/dockerizing-scala-redis-nginx/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.