Skip to content

Commit 05ed4e1

Browse files
Implement an ElasticSearchActivationStore (#4724)
* Implement an ElasticSearchActivationStore * Remove short headers and mismatched comments * typo fix * Use TestContainers * Neat changes * Update build.gradle * Fix TestContainers * fix mistake * Remove cache and add configuration example * Fix pureconfig * Apply review comments * Add result and annotations to mock WhiskActivations * Add instructions about how to use it * Update ansible/README.md * Remove vagrant changes * Add elasticsearch to `redo` and remove whitespace * Fix tests
1 parent 4c97dc1 commit 05ed4e1

File tree

24 files changed

+920
-5
lines changed

24 files changed

+920
-5
lines changed

ansible/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,46 @@ ansible-playbook -i environments/<environment> routemgmt.yml
191191
- To use the API Gateway, you'll need to run `apigateway.yml` and `routemgmt.yml`.
192192
- Use `ansible-playbook -i environments/<environment> openwhisk.yml` to avoid wiping the data store. This is useful to start OpenWhisk after restarting your Operating System.
193193

194+
### Using ElasticSearch to Store Activations
195+
196+
You can use ElasticSearch (ES) to store activations separately while other entities remain stored in CouchDB. There is an Ansible playbook to setup a simple ES cluster for testing and development purposes.
197+
198+
- Provide your custom ES related ansible arguments:
199+
200+
```
201+
elastic_protocol="http"
202+
elastic_index_pattern="openwhisk-%s" // this will be combined with namespace's name, so different namespace can use different index
203+
elastic_base_volume="esdata" // name of docker volume to store ES data
204+
elastic_cluster_name="openwhisk"
205+
elastic_java_opts="-Xms1g -Xmx1g"
206+
elastic_loglevel="INFO"
207+
elastic_username="admin"
208+
elastic_password="admin"
209+
elasticsearch_connect_string="x.x.x.x:9200,y.y.y.y:9200" // if you want to use an external ES cluster, add it
210+
```
211+
212+
- Then execute:
213+
214+
```
215+
cd <openwhisk_home>
216+
./gradlew distDocker
217+
cd ansible
218+
# couchdb is still needed to store subjects and actions
219+
ansible-playbook -i environments/<environment> couchdb.yml
220+
ansible-playbook -i environments/<environment> initdb.yml
221+
ansible-playbook -i environments/<environment> wipe.yml
222+
# this will deploy a simple ES cluster, you can skip this to use external ES cluster
223+
ansible-playbook -i environments/<environment> elasticsearch.yml
224+
ansible-playbook -i environments/<environment> openwhisk.yml -e db_activation_backend=ElasticSearch
225+
226+
# installs a catalog of public packages and actions
227+
ansible-playbook -i environments/<environment> postdeploy.yml
228+
229+
# to use the API gateway
230+
ansible-playbook -i environments/<environment> apigateway.yml
231+
ansible-playbook -i environments/<environment> routemgmt.yml
232+
```
233+
194234
### Configuring the installation of `wsk` CLI
195235
There are two installation modes to install `wsk` CLI: remote and local.
196236

ansible/elasticsearch.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
---
18+
# This playbook deploys a ElasticSearch cluster
19+
20+
- hosts: elasticsearch
21+
vars:
22+
#
23+
# host_group - usually "{{ groups['...'] }}" where '...' is what was used
24+
# for 'hosts' above. The hostname of each host will be looked up in this
25+
# group to assign a zero-based index. That index will be used in concert
26+
# with 'name_prefix' below to assign a host/container name.
27+
host_group: "{{ groups['elasticsearch'] }}"
28+
#
29+
# name_prefix - a unique prefix for this set of elasticsearches. The prefix
30+
# will be used in combination with an index (determined using
31+
# 'host_group' above) to name host/elasticsearcher.
32+
name_prefix: "elasticsearch"
33+
roles:
34+
- elasticsearch

ansible/environments/docker-machine/hosts.j2.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ invoker1 ansible_host={{ docker_machine_ip }}
3636
[apigateway]
3737
{{ docker_machine_ip }} ansible_host={{ docker_machine_ip }}
3838

39+
[elasticsearch:children]
40+
db
41+
3942
; define variables
4043
[all:vars]
4144
ansible_connection=ssh

ansible/environments/local/hosts.j2.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ invoker1 ansible_host=172.17.0.1 ansible_connection=local
3131
[db]
3232
172.17.0.1 ansible_host=172.17.0.1 ansible_connection=local
3333

34+
[elasticsearch:children]
35+
db
36+
3437
[redis]
3538
172.17.0.1 ansible_host=172.17.0.1 ansible_connection=local
3639

ansible/group_vars/all

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,27 @@ db:
272272
invoker:
273273
user: "{{ db_invoker_user | default(lookup('ini', 'db_username section=invoker file={{ playbook_dir }}/db_local.ini')) }}"
274274
pass: "{{ db_invoker_pass | default(lookup('ini', 'db_password section=invoker file={{ playbook_dir }}/db_local.ini')) }}"
275+
activation_store:
276+
backend: "{{ db_activation_backend | default('CouchDB') }}"
277+
elasticsearch:
278+
protocol: "{{ elastic_protocol | default('http') }}"
279+
port: 9200
280+
index_pattern: "{{ elastic_index_pattern | default('openwhisk-%s') }}"
281+
base_transport_port: 9300
282+
confdir: "{{ config_root_dir }}/elasticsearch"
283+
dir:
284+
become: "{{ elastic_dir_become | default(false) }}"
285+
base_volume: "{{ elastic_base_volume | default('esdata') }}"
286+
cluster_name: "{{ elastic_cluster_name | default('openwhisk') }}"
287+
java_opts: "{{ elastic_java_opts | default('-Xms1g -Xmx1g') }}"
288+
loglevel: "{{ elastic_loglevel | default('INFO') }}"
289+
# the user id of elasticsearch process, default is 1000, if you have enabled user namespace
290+
# for docker daemon, this need to be changed correspondingly
291+
uid: "{{ elastic_uid | default(1000) }}"
292+
auth:
293+
admin:
294+
username: "{{ elastic_username | default('admin') }}"
295+
password: "{{ elastic_password | default('admin') }}"
275296

276297
apigateway:
277298
port:
@@ -291,6 +312,15 @@ linux:
291312
couchdb:
292313
version: 2.3
293314

315+
elasticsearch:
316+
version: 6.7.2
317+
318+
elasticsearch_connect_string: "{% set ret = [] %}\
319+
{% for host in groups['elasticsearch'] %}\
320+
{{ ret.append( hostvars[host].ansible_host + ':' + ((db.elasticsearch.port+loop.index-1)|string) ) }}\
321+
{% endfor %}\
322+
{{ ret | join(',') }}"
323+
294324
docker:
295325
# The user to install docker for. Defaults to the ansible user if not set. This will be the user who is able to run
296326
# docker commands on a machine setup with prereq_build.yml

ansible/roles/controller/tasks/deploy.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,22 @@
275275
set_fact:
276276
env: "{{ env | combine(controller.extraEnv) }}"
277277

278+
- name: setup elasticsearch activation store env
279+
set_fact:
280+
elastic_env:
281+
"CONFIG_whisk_activationStore_elasticsearch_protocol": "{{ db.elasticsearch.protocol}}"
282+
"CONFIG_whisk_activationStore_elasticsearch_hosts": "{{ elasticsearch_connect_string }}"
283+
"CONFIG_whisk_activationStore_elasticsearch_indexPattern": "{{ db.elasticsearch.index_pattern }}"
284+
"CONFIG_whisk_activationStore_elasticsearch_username": "{{ db.elasticsearch.auth.admin.username }}"
285+
"CONFIG_whisk_activationStore_elasticsearch_password": "{{ db.elasticsearch.auth.admin.password }}"
286+
"CONFIG_whisk_spi_ActivationStoreProvider": "org.apache.openwhisk.core.database.elasticsearch.ElasticSearchActivationStoreProvider"
287+
when: db.activation_store.backend == "ElasticSearch"
288+
289+
- name: merge elasticsearch activation store env
290+
set_fact:
291+
env: "{{ env | combine(elastic_env) }}"
292+
when: db.activation_store.backend == "ElasticSearch"
293+
278294
- name: populate volumes for controller
279295
set_fact:
280296
controller_volumes:
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
---
18+
# Remove ElasticSearch server
19+
20+
- name: set elasticsearch container name and volume
21+
set_fact:
22+
elasticsearch_name: "{{ name_prefix ~ host_group.index(inventory_hostname) }}"
23+
volume_name: "{{ db.elasticsearch.base_volume ~ host_group.index(inventory_hostname) }}"
24+
25+
- name: remove ElasticSearch
26+
vars:
27+
elasticsearch_image: "{{ elasticsearch.docker_image | default('docker.elastic.co/elasticsearch/elasticsearch:' ~ elasticsearch.version ) }}"
28+
docker_container:
29+
name: "{{ elasticsearch_name }}"
30+
image: "{{ elasticsearch_image }}"
31+
keep_volumes: False
32+
state: absent
33+
ignore_errors: True
34+
35+
- name: remove ElasticSearch conf dir
36+
file:
37+
path: "{{ db.elasticsearch.confdir }}/{{ elasticsearch_name }}"
38+
state: absent
39+
become: "{{ db.elasticsearch.dir.become }}"
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
---
18+
# This role will run a ElasticSearch server on the db group
19+
20+
- name: set the vm.max_map_count to 262144
21+
sysctl:
22+
name: vm.max_map_count
23+
value: '262144'
24+
become: true
25+
26+
- name: set elasticsearch container name, volume and port
27+
set_fact:
28+
elasticsearch_name: "{{ name_prefix ~ host_group.index(inventory_hostname) }}"
29+
volume_name: "{{ db.elasticsearch.base_volume ~ host_group.index(inventory_hostname) }}"
30+
http_port: "{{ (db.elasticsearch.port|int) + host_group.index(inventory_hostname) }}"
31+
transport_port: "{{ (db.elasticsearch.base_transport_port|int) + host_group.index(inventory_hostname) }}"
32+
33+
- name: ensure elasticserach config directory is created with permissions
34+
file:
35+
path: "{{ db.elasticsearch.confdir }}/{{ elasticsearch_name }}"
36+
state: directory
37+
mode: 0755
38+
become: "{{ db.elasticsearch.dir.become }}"
39+
40+
# create volume direcotry if it's a directory path(not a named volume)
41+
- name: ensure elasticserach volume directory is created with permissions
42+
file:
43+
path: "{{ volume_name }}"
44+
state: directory
45+
mode: 0700
46+
owner: "{{ db.elasticsearch.uid }}"
47+
become: true
48+
when: volume_name is search("/")
49+
50+
- name: copy elasticsearch config file
51+
template:
52+
src: "elasticsearch.yml.j2"
53+
dest: "{{ db.elasticsearch.confdir }}/{{ elasticsearch_name }}/elasticsearch.yml"
54+
mode: 0644
55+
become: "{{ db.elasticsearch.dir.become }}"
56+
57+
- name: copy elasticsearch log config file
58+
template:
59+
src: "log4j2.properties.j2"
60+
dest: "{{ db.elasticsearch.confdir }}/{{ elasticsearch_name }}/log4j2.properties"
61+
mode: 0644
62+
become: "{{ db.elasticsearch.dir.become }}"
63+
64+
- name: "(re)start ElasticSearch from '{{ elasticsearch_image }} ' "
65+
vars:
66+
elasticsearch_image: "{{ elasticsearch.docker_image | default('docker.elastic.co/elasticsearch/elasticsearch:' ~ elasticsearch.version ) }}"
67+
docker_container:
68+
name: "{{ elasticsearch_name }}"
69+
image: "{{ elasticsearch_image }}"
70+
state: started
71+
recreate: true
72+
restart_policy: "{{ docker.restart.policy }}"
73+
ports:
74+
- "{{ http_port }}:9200"
75+
- "{{ transport_port }}:{{ transport_port }}"
76+
volumes:
77+
- "{{ db.elasticsearch.confdir }}/{{ elasticsearch_name }}/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml"
78+
- "{{ db.elasticsearch.confdir }}/{{ elasticsearch_name }}/log4j2.properties:/usr/share/elasticsearch/config/log4j2.properties"
79+
- "{{ volume_name }}:/usr/share/elasticsearch/data"
80+
pull: "{{ docker.pull_elasticsearch | default(true) }}"
81+
ulimits:
82+
- "nofile:262144:262144"
83+
- "memlock:-1:-1"
84+
env:
85+
TZ: "{{ docker.timezone }}"
86+
ES_JAVA_OPTS: "{{ db.elasticsearch.java_opts }}"
87+
88+
- name: wait until ElasticSearch in this host is up and running
89+
uri:
90+
url: "{{ db.elasticsearch.protocol }}://{{ ansible_host }}:{{ http_port }}"
91+
register: result
92+
until: result.status == 200
93+
retries: 12
94+
delay: 5
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
---
18+
# This role will deploy a database server. Use the role if you want to use ElasticSearch locally.
19+
# In deploy mode it will start the ElasticSearch container.
20+
# In clean mode it will remove the ElasticSearch container.
21+
22+
- import_tasks: deploy.yml
23+
when: mode == "deploy"
24+
25+
- import_tasks: clean.yml
26+
when: mode == "clean"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
cluster.name: "{{ db.elasticsearch.cluster_name }}"
2+
node.name: "{{ elasticsearch_name }}"
3+
network.host: 0.0.0.0
4+
network.publish_host: {{ ansible_default_ipv4.address }}
5+
6+
http.port: 9200
7+
transport.tcp.port: {{ transport_port }}
8+
9+
# minimum_master_nodes need to be explicitly set when bound on a public IP
10+
# set to 1 to allow single node clusters
11+
# Details: https://github.com/elastic/elasticsearch/pull/17282
12+
discovery.zen.ping.unicast.hosts:
13+
{% for es in groups['elasticsearch'] %}
14+
- {{ hostvars[es].ansible_host }}:{{ db.elasticsearch.base_transport_port + host_group.index(es)|int }}
15+
{% endfor %}
16+
discovery.zen.minimum_master_nodes: {{ (host_group|length / 2 + 1) | int}}
17+
18+
gateway.recover_after_nodes: {{ (host_group|length / 2 + 1) | int }}
19+
gateway.expected_nodes: {{ host_group|length }}
20+
gateway.recover_after_time: 5m
21+
22+
xpack.security.enabled: false
23+
bootstrap.memory_lock: true

0 commit comments

Comments
 (0)