Docker Solr FAQ =============== How do I persist Solr data and config? -------------------------------------- Your data is persisted already, in your container's filesystem. If you `docker run`, add data to Solr, then `docker stop` and later `docker start`, then your data is still there. The same is true for changes to configuration files. Equally, if you `docker commit` your container, you can later create a new container from that image, and that will have your data in it. For some use-cases it is convenient to provide a modified `solr.in.sh` file to Solr. For example to point Solr to a ZooKeeper host: ``` docker create --name my_solr -P solr docker cp my_solr:/opt/solr/bin/solr.in.sh . sed -i -e 's/#ZK_HOST=.*/ZK_HOST=cylon.lan:2181/' solr.in.sh docker cp solr.in.sh my_solr:/opt/solr/bin/solr.in.sh docker start my_solr # With a browser go to http://cylon.lan:32873/solr/#/ and confirm "-DzkHost=cylon.lan:2181" in the JVM Args section. ``` But usually when people ask this question, what they are after is a way to store Solr data and config in a separate [Docker Volume](https://docs.docker.com/userguide/dockervolumes/). That is explained in the next two questions. How can I mount a host directory as a data volume? -------------------------------------------------- This is useful if you want to inspect or modify the data in the Docker host when the container is not running, and later easily run new containers against that data. This is indeed possible, but there are a few gotchas. Solr stores its core data in the `server/solr` directory, in sub-directories for each core. The `server/solr` directory also contains configuration files that are part of the Solr distribution. Now, if we mounted volumes for each core individually, then that would interfere with Solr trying to create those directories. If instead we make the whole directory a volume, then we need to provide those configuration files in our volume, which we can do by copying them from a temporary container. For example: ``` # create a directory to store the server/solr directory $ mkdir /home/docker-volumes/mysolr1 # make sure its host owner matches the container's solr user $ sudo chown 8983:8983 /home/docker-volumes/mysolr1 # copy the solr directory from a temporary container to the volume $ docker run -it --rm -v /home/docker-volumes/mysolr1:/target apache/solr cp -r server/solr /target/ # pass the solr directory to a new container running solr $ SOLR_CONTAINER=$(docker run -d -P -v /home/docker-volumes/mysolr1/solr:/opt/solr/server/solr apache/solr) # create a new core $ docker exec -it --user=solr $SOLR_CONTAINER solr create_core -c gettingstarted # check the volume on the host: $ ls /home/docker-volumes/mysolr1/solr/ configsets gettingstarted README.txt solr.xml zoo.cfg ``` Note that if you add or modify files in that directory from the host, you must `chown 8983:8983` them. How can I use a Data Volume Container? -------------------------------------- You can avoid the concerns about UID mismatches above, by using data volumes only from containers. You can create a container with a volume, then point future containers at that same volume. This can be handy if you want to modify the solr image, for example if you want to add a program. By separating the data and the code, you can change the code and re-use the data. But there are pitfalls: - if you remove the container that owns the volume, then you lose your data. Docker does not even warn you that a running container is dependent on it. - if you point multiple solr containers at the same volume, you will have multiple instances write to the same files, which will undoubtedly lead to corruption - if you do want to remove that volume, you must do `docker rm -v containername`; if you forget the `-v` there will be a dangling volume which you can not easily clean up. Here is an example: ``` # create a container with a volume on the path that solr uses to store data. docker create -v /opt/solr/server/solr --name mysolr1data solr /bin/true # pass the volume to a new container running solr SOLR_CONTAINER=$(docker run -d -P --volumes-from=mysolr1data apache/solr) # create a new core $ docker exec -it --user=solr $SOLR_CONTAINER solr create_core -c gettingstarted # make a change to the config, using the config API docker exec -it --user=solr $SOLR_CONTAINER curl http://localhost:8983/solr/gettingstarted/config -H 'Content-type:application/json' -d'{ "set-property" : {"query.filterCache.autowarmCount":1000}, "unset-property" :"query.filterCache.size"}' # verify the change took effect docker exec -it --user=solr $SOLR_CONTAINER curl http://localhost:8983/solr/gettingstarted/config/overlay?omitHeader=true # stop the solr container docker exec -it --user=solr $SOLR_CONTAINER bash -c 'cd server; java -DSTOP.PORT=7983 -DSTOP.KEY=solrrocks -jar start.jar --stop' # create a new container SOLR_CONTAINER=$(docker run -d -P --volumes-from=mysolr1data apache/solr) # check our core is still there: docker exec -it --user=solr $SOLR_CONTAINER ls server/solr/gettingstarted # check the config modification is still there: docker exec -it --user=solr $SOLR_CONTAINER curl http://localhost:8983/solr/gettingstarted/config/overlay?omitHeader=true ``` Can I use volumes with SOLR_HOME? --------------------------------- Solr supports a SOLR_HOME environment variable to point to a non-standard location of the Solr home directory. You can use this in Solr docker, in combination with volumes: ``` docker run -it -v $PWD/mysolrhome:/mysolrhome -e SOLR_HOME=/mysolrhome apache/solr ``` This does need a pre-configured directory at that location. To make this easier, Solr docker supports a INIT_SOLR_HOME setting, which copies the contents from the default directory in the image to the SOLR_HOME (if it is empty). ``` mkdir mysolrhome sudo chown 8983:8983 mysolrhome docker run -it -v $PWD/mysolrhome:/mysolrhome -e SOLR_HOME=/mysolrhome -e INIT_SOLR_HOME=yes apache/solr ``` Note: If SOLR_HOME is set, the "solr-precreate" command will put the created core in the SOLR_HOME directory rather than the "mycores" directory. Can I run ZooKeeper and Solr clusters under Docker? --------------------------------------------------- At the network level the ZooKeeper nodes need to be able to talk to eachother, and the Solr nodes need to be able to talk to the ZooKeeper nodes and to each other. At the application level, different nodes need to be able to identify and locate each other. In ZooKeeper that is done with a configuration file that lists hostnames or IP addresses for each node. In Solr that is done with a parameter that specifies a host or IP address, which is then stored in ZooKeeper. In typical clusters, those hostnames/IP addresses are pre-defined and remain static through the lifetime of the cluster. In Docker, inter-container communication and multi-host networking can be facilitated by [Docker Networks](https://docs.docker.com/engine/userguide/networking/). But, crucially, Docker does not normally guarantee that IP addresses of containers remain static during the lifetime of a container. In non-networked Docker, the IP address seems to change everytime you stop/start. In a networked Docker, containers can lose their IP address in certain sequences of starting/stopping, unless you take steps to prevent that. IP changes causes problems: - If you use hardcoded IP addresses in configuration, and the addresses of your containers change after a stops/start, then your cluster will stop working and may corrupt itself. - If you use hostnames in configuration, and the addresses of your containers change, then you might run into problems with cached hostname lookups. - And if you use hostnames there is another problem: the names are not defined until the respective container is running, So when for example the first ZooKeeper node starts up, it will attempt a hostname lookup for the other nodes, and that will fail. This is especially a problem for ZooKeeper 3.4.6; future versions are better at recovering. Docker 1.10 has a new `--ip` configuration option that allows you to specify an IP address for a container. It also has a `--ip-range` option that allows you to specify the range that other containers get addresses from. Used together, you can implement static addresses. See [this example](docs/docker-networking.md). Can I run ZooKeeper and Solr with Docker Links? ----------------------------------------------- Docker's [Legacy container links](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/) provide a way to pass connection configuration between containers. It only works on a single machine, on the default bridge. It provides no facilities for static IPs. Note: this feature is expected to be deprecated and removed in a future release. So really, see the "Can I run ZooKeeper and Solr clusters under Docker?" option above instead. But for some use-cases, such as quick demos or one-shot automated testing, it can be convenient. Run ZooKeeper, and define a name so we can link to it: ```console $ docker run --name zookeeper -d -p 2181:2181 -p 2888:2888 -p 3888:3888 jplock/zookeeper ``` Run two Solr nodes, linked to the zookeeper container: ```console $ docker run --name solr1 --link zookeeper:ZK -d -p 8983:8983 \ apache/solr \ bash -c 'solr start -f -z $ZK_PORT_2181_TCP_ADDR:$ZK_PORT_2181_TCP_PORT' $ docker run --name solr2 --link zookeeper:ZK -d -p 8984:8983 \ apache/solr \ bash -c 'solr start -f -z $ZK_PORT_2181_TCP_ADDR:$ZK_PORT_2181_TCP_PORT' ``` Create a collection: ```console $ docker exec -i -t solr1 solr create_collection \ -c gettingstarted -shards 2 -p 8983 ``` Then go to `http://localhost:8983/solr/#/~cloud` (adjust the hostname for your docker host) to see the two shards and Solr nodes. How can I run ZooKeeper and Solr with Docker Compose? ----------------------------------------------------- See the [docker compose example](docs/docker-compose.yml). I'm confused about the different invocations of solr -- help? ------------------------------------------------------------- The different invocations of the Solr docker image can look confusing, because the name of the image is "apache/solr" and the Solr command is also "solr", and the image interprets various arguments in special ways. I'll illustrate the various invocations: To run an arbitrary command in the image: ``` docker run -it apache/solr date ``` here "apache/solr" is the name of the image, and "date" is the command. This does not invoke any solr functionality. To run the Solr server: ``` docker run -it apache/solr ``` Here "apache/solr" is the name of the image, and there is no specific command, so the image defaults to run the "solr" command with "-f" to run it in the foreground. To run the Solr server with extra arguments: ``` docker run -it apache/solr -h myhostname ``` This is the same as the previous one, but an additional argument is passed. The image will run the "solr" command with "-f -h myhostname" To run solr as an arbitrary command: ``` docker run -it apache/solr solr zk --help ``` here the first "apache/solr" is the image name, and the second "solr" is the "solr" command. The image runs the command exactly as specified; no "-f" is implicitly added. The container will print help text, and exit. If you find this visually confusing, it might be helpful to use more specific image tags, and specific command paths. For example: ``` docker run -it apache/solr:6 bin/solr -f -h myhostname ``` Finally, the Solr docker image offers several commands that do some work before then invoking the Solr server, like "solr-precreate" and "solr-demo". See the README.md for usage. These are implemented by the `docker-entrypoint.sh` script, and must be passed as the first argument to the image. For example: ``` docker run -it apache/solr:6 solr-demo ``` It's important to understand an implementation detail here. The Dockerfile uses `solr-foreground` as the `CMD`, and the `docker-entrypoint.sh` implements that by by running "solr -f". So these two are equivalent: ``` docker run -it apache/solr:6 docker run -it apache/solr:6 solr-foreground ``` whereas: ``` docker run -it apache/solr:6 solr -f ``` is slightly different: the "solr" there is a generic command, not treated in any special way by `docker-entrypoint.sh`. In particular, this means that the `docker-entrypoint-initdb.d` mechanism is not applied. So, if you want to use `docker-entrypoint-initdb.d`, then you must use one of the other two invocations. You also need to keep that in mind when you want to invoke solr from the bash command. For example, this does NOT run `docker-entrypoint-initdb.d` scripts: ``` docker run -it -v $PWD/set-heap.sh:/docker-entrypoint-initdb.d/set-heap.sh \ apache/solr:6 bash -c "echo hello; solr -f" ``` but this does: ``` docker run -it $PWD/set-heap.sh:/docker-entrypoint-initdb.d/set-heap.sh \ apache/solr:6 bash -c "echo hello; /opt/docker-solr/scripts/docker-entrypoint.sh solr-foreground" ```