If you're developing a chatbot with Rasa, no doubt you've gone down the same path as me and opened multiple consoles / terminals to launch the Rasa server, Action server, Duckling, your webchat ui and possibly more depending on how advanced your bot has become.
This is a really easy way to develop, although unless your terminal app can do tabs, it becomes quite tiresome tracking down the proper one to restart.
I'm going to show you how you can setup docker to launch them all with one command, and give you the flexibility to watch the logs, connect directly to a service, and of course stop and restart them when needed.
We're going to use the
docker-compose.yml file to achieve this.
docker-compose.yml file is a configuration file that tells docker how to build a stack of containers. That means, it will fire up a single container for each service (chat server / action server / chatUI / etc.) all with one command. It's pretty sweet, especially if you're used to opening up multiple consoles to launch each service like I mentioned above.
I've attached my
docker-compose.yml file to this post in case you want to just jump ahead, because who has time to actually read blog posts these days. Am I right?
If you do happen to have time, good for you, I'm going to explain how to get this working, and you'll be 30 minutes ahead of the people that skipped this section, wondering why my file didn't work straight away.
If you have a Rasa project, you can download and drop my file into the root of your project. My file assumes your
actions.py (and other action files) are located in an
actions directory off your project directory. If you followed my post about the actions files, then you're good to skip the next section.
To use my file as-is, you just need to do a couple things
- create an actions directory off your project root
__init.py__from your project root into it
For more information about the actions files and the actions directory read my post here
We're going to talk briefly about a few of the config options in the
First up is volumes. The volumes option takes an array of values, meaning you indent and use a hypen ( - ) for each item. The items here are directories you want to map to docker. In my file the
volumes section looks like this for the rasa-server service:
volumes: - ./:/app
You can see the value on the
volumes: line is split with a :. This tells Docker what local directory (the left side of the :) to make available to the service container and where in the container (right side of the :) to mount them to.
You end up with something like
./:/app That looks like a lot of dots and slashes, but essentially it is saying to map the current local project directory ./ to /app in the container. The result if this notation is that all files and directories in the project folder (think configuration, models, nlu data, etc) are made available to the rasa server container when it's fired up.
This makes sense if you think about it because the server requires all of those config files and your models in order to run. It would be useless if you couldn't get your models or configuration to be read by Rasa in the container.
To beat a dead horse, we'll look at the
volumes: value for the action-server service configuration. It is similar.
volumes: - ./actions:/app/actions
I know what you may be thinking, we just told docker to use the entire project directory (including the actions directory), why do we need to do it again?
you'll notice in the
docker-compose.yml file there are different sections called
services:. We have a
rasa-server service and an
action-server service. Docker allows us to configure each one independently giving us some crazy flexibility and allows us to tune each service to use only what it needs.
You also may be thinking, why didn't you use the same
./:/app value from the
rasa-server? You could and it would work, but that would bloat the action-server container because it would also have access to the models and other config data. Best practices say to limit access to just what is needed and make your containers as small as possible.
Back to the beating that horse with actual value now.
volumes: - ./actions:/app/actions
The actions server is mounting the actions directory we created above (./actions) and making it available at /app/actions inside the action-server container. The action server docker image that is being pulled, knows to load the actions from it's local /app/actions directory. Make sense?
volume: parameter is important because it allows outside files into the container, meaning data can be saved from the container to the volume and will persist next time you run the container. The same in reverse as well. If you make changes to your
stories.md, or any other config file, and retrain rasa, you just stop and restart the container and it will use your new models and configuration.
These volume mappings allow you to continue to develop / train, etc locally with Docker and have your data and configuration persist.
Provided you have the requirements mentioned at the top of this article, it is pretty easy to use docker compose.
Drop the file into your rasa project directory run
docker-compose up and should be good to go.
docker-compose up will keep the terminal live, and you'll see all the logs for each of the services you're firing up. You would use CTRL+C to stop everything.
You can also run
docker-compose up -d and that will launch them in the background and give you your terminal back. To then stop them all if running in the background, run
docker-compose down and they'll all stop.
One thing that may (or may not be) obvious is that you need to be in the same directory as your
docker-compose.yml file to run these commands. Since that is our configuration file, docker compose uses that to know what to launch or stop.
When I first started out, I never used the
-d flag because I like to watch logs as I test and develop. This is especially useful if you're starting out because you can immediately spot issues with configurations, etc. But, after a while you'll want to fire this off and you'll want your cursor back :)
-d flag is handy because they run in the background. This allows you to be able to stop different containers of needed, so if for example you're editing your actions.py file, you can just stop and restart the action server instead of bouncing all of your containers each time. That is ok if you do this, to me it is just a waste of time.
First you need to know the name of your container. To get a list of your running containers, run
docker ps. You'll see something like this:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES af21abaf9997 rasa/rasa:1.9.0 "rasa run --cors * -…" 2 hours ago Up 8 seconds 0.0.0.0:5005->5005/tcp rasa-r2-server f631aa0cd485 mysql:5.7 "docker-entrypoint.s…" 2 hours ago Up 8 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp mysql-rasa-r2 e18dc702ff5b rasa/rasa-sdk:1.9.0 "./entrypoint.sh sta…" 2 hours ago Up 8 seconds 0.0.0.0:5055->5055/tcp rasa-r2-action-server
If you wanted to restart the action server for example, you can take the
CONTAINER ID for the action server (the bottom one) and run
docker container restart e18dc702ff5b
When that's completed, you can look with
docker ps again and see it was restarted under the CREATED column
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES af21abaf9997 rasa/rasa:1.9.0 "rasa run --cors * -…" 2 hours ago Up 3 minutes 0.0.0.0:5005->5005/tcp rasa-r2-server f631aa0cd485 mysql:5.7 "docker-entrypoint.s…" 2 hours ago Up 3 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp mysql-rasa-r2 e18dc702ff5b rasa/rasa-sdk:1.9.0 "./entrypoint.sh sta…" 2 hours ago Up 29 seconds 0.0.0.0:5055->5055/tcp rasa-r2-action-server
For those of you still reading, here's some coolness that we've implemented that you didn't even know about.
Those hashes change each time a container is launched, and are a pain to deal with especially if you need to bounce a container a lot during development.
You'll notice that each container has an actual name (NAME column), our action server is named
rasa-r2-action-server whether you realized it or not, we defined this in our file with the parameter
container-name:. Now we know what the container will be called all the time, it won't change no matter how many times you bounce it.
You can use this name to restart the container like this:
docker container restart rasa-r2-action-server
That makes it easier to restart because now you don't need to always get the new hash with
If you leave out the
container-name: parameter in
docker-compose.yml, docker will auto generate a name for the container which is fine, but not ideal, it is just easier to give each of our containers a name, then we dictate what it is called.
Occasionally you may need to forcibly kill a container, or even just stop one for a while instead of restarting it. This is very similar to restarting a container, you just use the keyword
docker kill rasa-r2-action-server If you run
docker ps you'll see it is now gone.
Great, you've killed a service using the container name, fixed whatever the issue is and want to fire it up again? Well you'd think you can access it via the container name because that's what we've done in the other sections. Don't be fooled, there is no container with the name of the one you just stopped. We need to access it by the service name. In our example you'd run
docker-compose up -d action-server where
action-server is the service name defined in
docker ps and you'll see it is fired back up.
It can be quite important to look at the logs in the event something does wrong. You can use the container name we defined above and watch the logs like this:
docker logs rasa-r2-action-server -f
2020-05-20 16:38:04 INFO rasa_sdk.endpoint - Starting action endpoint server... 2020-05-20 16:38:04 INFO rasa_sdk.executor - Registered function for 'action_hello_world'.
I added the
-f flag to keep the logs active. This command will take over the terminal and display changes to the log in real-time. Hit CTRL+C to stop and get your terminal back.
For Rasa, it would be rare for you to need to ssh into a container, but I'll round out the article with how to do that in case you need to verify some library version or something.
docker exec -it rasa-r2-server bash
This will drop you into the /app directory and you'll be inside the container. You can run something like
rasa --version or
python --version, or
pip list whatever you need to. Just type
exit to pop back out.
Take a look at the docker compose docs, there are some other useful commands like
top, etc that may prove useful as you get more into developing using docker.
Here's a link to the file I use
That is everything you need to know to develop Rasa using Docker. If you notice something I typed or said incorrectly, please let me know and I'll fix it right away. I tried to perform these examples as I wrote this, hopefully everything works for you. Good luck!