├── .gitignore ├── LICENSE ├── README.md ├── app ├── Dockerfile └── main.go ├── docker-compose.containers.yml └── docker-compose.local.yml /.gitignore: -------------------------------------------------------------------------------- 1 | /data 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2016 Oliver Eilhard 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the “Software”), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elastic on Docker (v6) 2 | 3 | This is a small example of how to use [Elastic](https://github.com/olivere/elastic) for Elasticsearch 6.x with [Docker](https://docs.docker.com/) and [Docker Compose](https://docs.docker.com/compose/). 4 | 5 | We use Docker Compose to orchestrates the containers. I've been using it successfully with Docker Compose 1.19+. The Docker compose configuration files use version 3 (see [here](https://docs.docker.com/compose/compose-file/compose-versioning/) for Docker Compile file versioning matrix). 6 | 7 | Notice there are two official Elasticsearch 6.x images: The OSS image at `docker.elastic.co/elasticsearch/elasticsearch-oss:6.3.1` (which we use here as default) and the full image `docker.elastic.co/elasticsearch/elasticsearch:6.3.1`. You need a license for the latter after a grace period. For more information, read the [official documentation on Installing Elasticsearch with Docker](https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html). 8 | 9 | Make sure to create a `./data` directory locally and uncomment the `volumnes` section in Docker Compose file(s) if you want your data to be persistent. 10 | 11 | The examples are split into two configurations. The first is for running Elasticsearch and a test application inside containers with Docker Compose. The second is for running Elasticsearch inside Docker only, but running the test application on the host. 12 | 13 | ## Containers 14 | 15 | This section describes how to run both Elasticsearch and the application inside Docker containers. 16 | 17 | Use the `docker-compose.containers.yml` file for starting the setup via Docker Compose. Notice that the test application might restart several times before Elasticsearch becomes available. 18 | 19 | ``` 20 | $ docker-compose -f docker-compose.containers.yml up --build 21 | ... 22 | app_1 | 2018/07/14 11:52:12 main.go:50: Looking up hostname "elasticsearch" 23 | app_1 | 2018/07/14 11:52:12 main.go:55: Lookup for hostname "elasticsearch" returns the following IPs: 24 | app_1 | 2018/07/14 11:52:12 main.go:57: 172.18.0.2 25 | app_1 | 2018/07/14 11:52:12 main.go:62: Retrieving http://elasticsearch:9200: 26 | app_1 | 2018/07/14 11:52:13 main.go:72: { 27 | app_1 | "name" : "5dd3if1", 28 | app_1 | "cluster_name" : "escontainers", 29 | app_1 | "cluster_uuid" : "8SdPtWC_SVm2supbip2Bwg", 30 | app_1 | "version" : { 31 | app_1 | "number" : "6.3.1", 32 | app_1 | "build_flavor" : "oss", 33 | app_1 | "build_type" : "tar", 34 | app_1 | "build_hash" : "eb782d0", 35 | app_1 | "build_date" : "2018-06-29T21:59:26.107521Z", 36 | app_1 | "build_snapshot" : false, 37 | app_1 | "lucene_version" : "7.3.1", 38 | app_1 | "minimum_wire_compatibility_version" : "5.6.0", 39 | app_1 | "minimum_index_compatibility_version" : "5.0.0" 40 | app_1 | }, 41 | app_1 | "tagline" : "You Know, for Search" 42 | app_1 | } 43 | app_1 | 2018/07/14 11:52:13 main.go:77: Retrieving http://elasticsearch:9200/_nodes/http?pretty=true: 44 | app_1 | 2018/07/14 11:52:13 main.go:87: { 45 | app_1 | "_nodes" : { 46 | app_1 | "total" : 1, 47 | app_1 | "successful" : 1, 48 | app_1 | "failed" : 0 49 | app_1 | }, 50 | app_1 | "cluster_name" : "escontainers", 51 | app_1 | "nodes" : { 52 | app_1 | "5dd3if1pThS5LAY6VX1rbQ" : { 53 | app_1 | "name" : "5dd3if1", 54 | app_1 | "transport_address" : "172.18.0.2:9300", 55 | app_1 | "host" : "172.18.0.2", 56 | app_1 | "ip" : "172.18.0.2", 57 | app_1 | "version" : "6.3.1", 58 | app_1 | "build_flavor" : "oss", 59 | app_1 | "build_type" : "tar", 60 | app_1 | "build_hash" : "eb782d0", 61 | app_1 | "roles" : [ 62 | app_1 | "master", 63 | app_1 | "data", 64 | app_1 | "ingest" 65 | app_1 | ], 66 | app_1 | "http" : { 67 | app_1 | "bound_address" : [ 68 | app_1 | "0.0.0.0:9200" 69 | app_1 | ], 70 | app_1 | "publish_address" : "172.18.0.2:9200", 71 | app_1 | "max_content_length_in_bytes" : 104857600 72 | app_1 | } 73 | app_1 | } 74 | app_1 | } 75 | app_1 | } 76 | app_1 | 2018/07/14 11:52:13 main.go:90: Connecting to http://elasticsearch:9200 77 | app_1 | 2018/07/14 11:52:13 main.go:95: Connected to http://elasticsearch:9200 78 | app_1 | 2018/07/14 11:52:13 main.go:135: Cluster "escontainers" with 1 node(s) 79 | app_1 | 2018/07/14 11:52:13 main.go:137: - Node 5dd3if1pThS5LAY6VX1rbQ with IP 172.18.0.2 80 | app_1 | 2018/07/14 11:52:23 main.go:135: Cluster "escontainers" with 1 node(s) 81 | ... 82 | ``` 83 | 84 | To stop everything, run: 85 | 86 | ``` 87 | $ docker-compose -f docker-compose.containers.yml down 88 | ``` 89 | 90 | ## Local 91 | 92 | This section describes how to run Elasticsearch inside Docker only, and running the test application on the host. 93 | 94 | Use the `docker-compose.local.yml` file for starting the setup via Docker Compose. Again, notice that this only starts Elasticsearch and makes it accessible locally on the host. 95 | 96 | ``` 97 | $ docker-compose -f docker-compose.local.yml up 98 | ``` 99 | 100 | Once Elasticsearch is successfully started, switch to a second console and run the test application. Notice that we need to pass the `-url=http://localhost:9200` parameter as Elasticsearch is configured to listen on that IP/port. 101 | 102 | ``` 103 | $ cd app 104 | $ go run main.go -url http://localhost:9200 105 | 2018/07/14 13:59:36 main.go:50: Looking up hostname "localhost" 106 | 2018/07/14 13:59:36 main.go:55: Lookup for hostname "localhost" returns the following IPs: 107 | 2018/07/14 13:59:36 main.go:57: ::1 108 | 2018/07/14 13:59:36 main.go:57: 127.0.0.1 109 | 2018/07/14 13:59:36 main.go:62: Retrieving http://localhost:9200: 110 | 2018/07/14 13:59:36 main.go:72: { 111 | "name" : "t-Hcpbj", 112 | "cluster_name" : "docker-cluster", 113 | "cluster_uuid" : "zOFxQHUCTy2V3y45JiO2yg", 114 | "version" : { 115 | "number" : "6.3.1", 116 | "build_flavor" : "oss", 117 | "build_type" : "tar", 118 | "build_hash" : "eb782d0", 119 | "build_date" : "2018-06-29T21:59:26.107521Z", 120 | "build_snapshot" : false, 121 | "lucene_version" : "7.3.1", 122 | "minimum_wire_compatibility_version" : "5.6.0", 123 | "minimum_index_compatibility_version" : "5.0.0" 124 | }, 125 | "tagline" : "You Know, for Search" 126 | } 127 | 2018/07/14 13:59:36 main.go:77: Retrieving http://localhost:9200/_nodes/http?pretty=true: 128 | 2018/07/14 13:59:36 main.go:87: { 129 | "_nodes" : { 130 | "total" : 1, 131 | "successful" : 1, 132 | "failed" : 0 133 | }, 134 | "cluster_name" : "docker-cluster", 135 | "nodes" : { 136 | "t-HcpbjwQX-h8KW8wwtv0w" : { 137 | "name" : "t-Hcpbj", 138 | "transport_address" : "127.0.0.1:9300", 139 | "host" : "127.0.0.1", 140 | "ip" : "127.0.0.1", 141 | "version" : "6.3.1", 142 | "build_flavor" : "oss", 143 | "build_type" : "tar", 144 | "build_hash" : "eb782d0", 145 | "roles" : [ 146 | "master", 147 | "data", 148 | "ingest" 149 | ], 150 | "http" : { 151 | "bound_address" : [ 152 | "172.18.0.2:9200", 153 | "127.0.0.1:9200" 154 | ], 155 | "publish_address" : "127.0.0.1:9200", 156 | "max_content_length_in_bytes" : 104857600 157 | } 158 | } 159 | } 160 | } 161 | 2018/07/14 13:59:36 main.go:90: Connecting to http://localhost:9200 162 | 2018/07/14 13:59:37 main.go:95: Connected to http://localhost:9200 163 | 2018/07/14 13:59:37 main.go:135: Cluster "docker-cluster" with 1 node(s) 164 | 2018/07/14 13:59:37 main.go:137: - Node t-HcpbjwQX-h8KW8wwtv0w with IP 127.0.0.1 165 | ... 166 | ``` 167 | 168 | To stop everything, quit the test application, then run: 169 | 170 | ``` 171 | $ docker-compose -f docker-compose.local.yml down 172 | ``` 173 | 174 | ## LICENSE 175 | 176 | MIT 177 | -------------------------------------------------------------------------------- /app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.11 2 | 3 | WORKDIR /go/src/app 4 | COPY . . 5 | 6 | # ENV GO111MODULE=on 7 | 8 | RUN go get -u github.com/olivere/elastic 9 | 10 | CMD ["go", "run", "main.go"] 11 | -------------------------------------------------------------------------------- /app/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "net" 10 | "net/http" 11 | "net/url" 12 | "os" 13 | "os/signal" 14 | "runtime" 15 | "sort" 16 | "syscall" 17 | "time" 18 | 19 | "github.com/olivere/elastic" 20 | ) 21 | 22 | func main() { 23 | var ( 24 | esURL = flag.String("url", "http://elasticsearch:9200", "Elasticsearch connection string") 25 | ) 26 | flag.Parse() 27 | 28 | if *esURL == "" { 29 | log.Fatal("missing -url flag") 30 | } 31 | url, err := url.Parse(*esURL) 32 | if err != nil { 33 | log.Fatalf("invalid -url flag: %v", err) 34 | } 35 | 36 | if len(os.Args) > 1 { 37 | switch os.Args[1] { 38 | case "showenv": 39 | log.Println("Environment") 40 | env := os.Environ() 41 | sort.Strings(env) 42 | for _, e := range env { 43 | log.Printf("- %s", e) 44 | } 45 | os.Exit(0) 46 | } 47 | } 48 | 49 | log.SetFlags(log.LstdFlags | log.Lshortfile) 50 | 51 | log.Printf("Running %s\n", runtime.Version()) 52 | log.Printf("Version of github.com/olivere/elastic: %s\n", elastic.Version) 53 | 54 | log.Printf("Looking up hostname %q", url.Hostname()) 55 | ips, err := net.LookupIP(url.Hostname()) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | log.Printf("Lookup for hostname %q returns the following IPs:", url.Hostname()) 60 | for _, ip := range ips { 61 | log.Printf("%v", ip) 62 | } 63 | 64 | // Check ES version and status 65 | { 66 | log.Printf("Retrieving %s:", *esURL) 67 | res, err := http.Get(*esURL) 68 | if err != nil { 69 | log.Fatal(err) 70 | } 71 | defer res.Body.Close() 72 | body, err := ioutil.ReadAll(res.Body) 73 | if err != nil { 74 | log.Fatal(err) 75 | } 76 | log.Printf("%v", string(body)) 77 | } 78 | 79 | // Check ES nodes configuration 80 | { 81 | log.Printf("Retrieving %s:", *esURL+"/_nodes/http?pretty=true") 82 | res, err := http.Get(*esURL + "/_nodes/http?pretty=true") 83 | if err != nil { 84 | log.Fatal(err) 85 | } 86 | defer res.Body.Close() 87 | body, err := ioutil.ReadAll(res.Body) 88 | if err != nil { 89 | log.Fatal(err) 90 | } 91 | log.Printf("%v", string(body)) 92 | } 93 | 94 | log.Printf("Connecting to %s", *esURL) 95 | client, err := elastic.NewClient(elastic.SetURL(*esURL)) 96 | if err != nil { 97 | log.Fatal(err) 98 | } 99 | log.Printf("Connected to %s", *esURL) 100 | 101 | errc := make(chan error) 102 | 103 | go func() { 104 | err := showNodes(client) 105 | if err != nil { 106 | log.Printf("nodes info failed: %v", err) 107 | } 108 | 109 | t := time.NewTicker(10 * time.Second) 110 | defer t.Stop() 111 | for { 112 | select { 113 | case <-t.C: 114 | err := showNodes(client) 115 | if err != nil { 116 | log.Printf("nodes info failed: %v", err) 117 | } 118 | } 119 | } 120 | }() 121 | 122 | go func() { 123 | c := make(chan os.Signal, 1) 124 | signal.Notify(c, syscall.SIGTERM, syscall.SIGINT) 125 | log.Printf("existing with signal %v", fmt.Sprint(<-c)) 126 | errc <- nil 127 | }() 128 | 129 | if err := <-errc; err != nil { 130 | os.Exit(1) 131 | } 132 | } 133 | 134 | func showNodes(client *elastic.Client) error { 135 | ctx := context.Background() 136 | info, err := client.NodesInfo().Do(ctx) 137 | if err != nil { 138 | return err 139 | } 140 | log.Printf("Cluster %q with %d node(s)", info.ClusterName, len(info.Nodes)) 141 | for id, node := range info.Nodes { 142 | log.Printf("- Node %s with IP %s", id, node.IP) 143 | } 144 | return nil 145 | } 146 | -------------------------------------------------------------------------------- /docker-compose.containers.yml: -------------------------------------------------------------------------------- 1 | # Run both the app and Elasticsearch inside Docker containers. 2 | version: '3' 3 | 4 | services: 5 | app: 6 | build: ./app 7 | restart: on-failure 8 | depends_on: 9 | - elasticsearch 10 | links: 11 | - elasticsearch 12 | 13 | elasticsearch: 14 | # This is the OSS image, which comes without X-Pack, ML etc. 15 | image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.0 16 | # This is the full image which includes everything but needs a license after some grace period. 17 | # image: docker.elastic.co/elasticsearch/elasticsearch:6.4.0 18 | 19 | # Make ES available both on _local_ and _site_ 20 | # See here for details on network configuration: 21 | # https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-network.html 22 | # command: elasticsearch -Enetwork.host=_local_,_site_ -Enetwork.publish_host=_local_ 23 | 24 | environment: 25 | # Set the cluster name (optional) 26 | - cluster.name=escontainers 27 | - bootstrap.memory_lock=true 28 | # - http.host=0.0.0.0 29 | # - transport.host=127.0.0.1 30 | # X-Pack is only in the full ES image, not the OSS image. 31 | # - xpack.security.enabled=false 32 | - "ES_JAVA_OPTS=-Xms1g -Xmx1g" 33 | # Some useful ulimits 34 | ulimits: 35 | nproc: 65536 36 | nofile: 37 | soft: 65536 38 | hard: 65536 39 | memlock: 40 | soft: -1 41 | hard: -1 42 | ports: 43 | - 9200:9200 44 | # volumes: 45 | # # Make sure to create the ./data folder before starting 46 | # - ./data:/usr/share/elasticsearch/data 47 | -------------------------------------------------------------------------------- /docker-compose.local.yml: -------------------------------------------------------------------------------- 1 | # Run Elasticsearch in Docker only. The app will be run on the host. 2 | version: '3' 3 | 4 | services: 5 | elasticsearch: 6 | # This is the OSS image, which comes without X-Pack, ML etc. 7 | image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.4.0 8 | # This is the full image which includes everything but needs a license after some grace period. 9 | # image: docker.elastic.co/elasticsearch/elasticsearch:6.4.0 10 | 11 | # Make ES available both on _local_ and _site_, 12 | # and use use _local_ for the publish_host. 13 | # 14 | # See here for details on network configuration: 15 | # https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-network.html 16 | command: elasticsearch -Enetwork.host=_local_,_site_ -Enetwork.publish_host=_local_ 17 | 18 | environment: 19 | # Set the cluster name (optional) 20 | - cluster.name=eslocal 21 | - bootstrap.memory_lock=true 22 | # - http.host=0.0.0.0 23 | # - transport.host=127.0.0.1 24 | # X-Pack is only in the full ES image, not the OSS image. 25 | # - xpack.security.enabled=false 26 | - "ES_JAVA_OPTS=-Xms1g -Xmx1g" 27 | # Some useful ulimits 28 | ulimits: 29 | nproc: 65536 30 | nofile: 31 | soft: 65536 32 | hard: 65536 33 | memlock: 34 | soft: -1 35 | hard: -1 36 | ports: 37 | - 9200:9200 38 | # volumes: 39 | # # Make sure to create the ./data folder before starting 40 | # - ./data:/usr/share/elasticsearch/data 41 | --------------------------------------------------------------------------------