1 .. This work is licensed under a Creative Commons Attribution 4.0 International License.
2 .. http://creativecommons.org/licenses/by/4.0
5 .. _docs_vfw_edgex_multicloud_k8s:
7 vFW/Edgex with Multicloud Kubernetes Plugin: Setting Up and Configuration
8 -------------------------------------------------------------------------
12 This use case covers the deployment of vFW and Edgex HELM Charts in a Kubernetes based cloud region via the multicloud-k8s plugin.
13 The multicloud-k8s plugin provides APIs to upload self-contained HELM Charts that can be customized via the profile API and later installed in a particular cloud region.
15 When the installation is complete (all the pods are either in running or completed state)
20 https://github.com/onap/multicloud-k8s/tree/master/kud/demo/firewall
22 EdgeXFoundry Helm Chart link:
23 -----------------------------
25 https://github.com/onap/multicloud-k8s/tree/master/kud/tests/vnfs/edgex/helm/edgex
28 **Create CSAR with Helm chart as an artifact**
29 ----------------------------------------------
31 The CSAR is a heat template package with Helm chart in it. The basic package
32 consists of an **environment file**, **base_dummy.yaml file** (example),
33 **MANIFEST.json** and the **tar.gz** file (of Helm chart).
34 We need to zip all of these files before onboarding.
35 One thing to pay much attention to is the naming convention which must
36 be followed while making the tgz.
37 **NOTE: The Naming convention is for the helm chart tgz file.**
39 **Naming convention follows the format:**
41 <free format string>\_\ ***cloudtech***\ \_<technology>\_<subtype>.extension
43 1. *Cloudtech:* is a fixed pattern and should not be changed if not
45 2. *Technology:* k8s, azure, aws
46 3. *Subtype*: charts, day0, config template
47 4. *Extension*: zip, tgz, csar
49 NOTE: The .tgz file must be a tgz created from the top level helm chart
50 folder. I.e. a folder that contains a Chart.yaml file in it.
51 For vFW use case the content of tgz file must be following
54 $ helm package firewall
56 $ tar -tf firewall-0.1.0.tgz
60 firewall/templates/onap-private-net.yaml
61 firewall/templates/_helpers.tpl
62 firewall/templates/protected-private-net.yaml
63 firewall/templates/deployment.yaml
64 firewall/templates/unprotected-private-net.yaml
66 firewall/charts/sink/.helmignore
67 firewall/charts/sink/Chart.yaml
68 firewall/charts/sink/templates/configmap.yaml
69 firewall/charts/sink/templates/_helpers.tpl
70 firewall/charts/sink/templates/service.yaml
71 firewall/charts/sink/templates/deployment.yaml
72 firewall/charts/sink/values.yaml
73 firewall/charts/packetgen/.helmignore
74 firewall/charts/packetgen/Chart.yaml
75 firewall/charts/packetgen/templates/_helpers.tpl
76 firewall/charts/packetgen/templates/deployment.yaml
77 firewall/charts/packetgen/values.yaml
81 Listed below is an example of the contents inside a heat template
86 MANIFEST.json base_dummy.env base_dummy.yaml
87 vfw_cloudtech_k8s_charts.tgz vfw_k8s_demo.zip
95 Key thing is note the addition of cloud artifact
98 type: "CLOUD_TECHNOLOGY_SPECIFIC_ARTIFACTS"
105 "file": "base_dummy.yaml",
110 "file": "base_dummy.env",
116 "file": "vfw_cloudtech_k8s_charts.tgz",
117 "type": "CLOUD_TECHNOLOGY_SPECIFIC_ARTIFACTS"
123 ~~~~~~~~~~~~~~~~~~~~~
124 Designed to be minimal HEAT template
128 ##==================LICENSE_START========================================
130 ## Copyright (C) 2019 Intel Corporation
131 ## SPDX-License-Identifier: Apache-2.0
133 ##==================LICENSE_END===========================================
135 heat_template_version: 2016-10-14
136 description: Heat template to deploy dummy VNF
142 description: Dummy name
146 label: id of vnommand to read (GET) Definition
147 description: Provided by ONAP
152 description: Provided by ONAP
157 description: Provided by ONAP
161 label: Image name or ID
162 description: Dummy image name
167 description: Dummy flavor
171 type: OS::Nova::Server
173 name: { get_param: dummy_name_0 }
174 image: { get_param: dummy_image_name }
175 flavor: { get_param: dummy_flavor_name } metadata: { vnf_name: { get_param: vnf_name }, vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }}
187 vnf_id: PROVIDED_BY_ONAP
188 vnf_name: PROVIDED_BY_ONAP
189 vf_module_id: PROVIDED_BY_ONAP
190 dummy_name_0: dummy_1_0
191 dummy_image_name: dummy
192 dummy_flavor_name: dummy.default
197 For onboarding instructions please refer to steps 4-9 from the document
198 `here <https://wiki.onap.org/display/DW/vFWCL+instantiation%2C+testing%2C+and+debuging>`__.
200 **Steps for installing KUD Cloud**
201 ----------------------------------
203 Follow the link to install KUD Kubernetes Deployment. KUD contains all
204 the packages required for running vfw use case.
206 Kubernetes Baremetal deployment instructions here_
208 .. _here: https://wiki.onap.org/display/DW/Kubernetes+Baremetal+deployment+setup+instructions/
210 **REGISTER KUD CLOUD REGION with K8s-Plugin**
211 ---------------------------------------------
213 API to support Reachability for Kubernetes Cloud
215 **The command to POST connectivity info**
216 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
220 "cloud-region" : "<name>", // Must be unique across
221 "cloud-owner" : "<owner>",
222 "other-connectivity-list" : {
225 This is a multipart upload and here is how you do the POST for this.
227 #Using a json file (eg: post.json) containing content as above
230 curl -i -F "metadata=<post.json;type=application/json" -F file=@
231 /home/ad_kkkamine/.kube/config -X POST http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/connectivity-info
233 **Command to GET Connectivity Info**
234 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
238 curl -i -X GET http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/connectivity-info/{name}
241 **Command to DELETE Connectivity Info**
242 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
246 curl -i -X GET http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/connectivity-info/{name}
249 **Command to UPDATE/PUT Connectivity Info**
250 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
254 curl -i -X GET http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/connectivity-info/{name}
256 **Register KUD Cloud region with AAI**
257 --------------------------------------
259 With k8s cloud region, we need to add a tenant to the k8s cloud region.
260 The 'easy' way is to have the ESR information (in step 1 of cloud
261 registration) point to a real OpenStack tenant (e.g. the OOF tenant in
262 the lab where we tested).
264 This will cause multicloud to add the tenant to the k8s cloud region and
265 then, similar to #10 in the documentation
266 `here <https://onap.readthedocs.io/en/casablanca/submodules/integration.git/docs/docs_vfwHPA.html#docs-vfw-hpa>`__,
267 the service-subscription can be added to that object.
269 NOTE: use same name cloud-region and cloud-owner name
271 An example is shown below for K8s cloud but following the steps 1,2,3
273 `here <https://onap.readthedocs.io/en/latest/submodules/multicloud/framework.git/docs/multicloud-plugin-windriver/UserGuide-MultiCloud-WindRiver-TitaniumCloud.html#tutorial-onboard-instance-of-wind-river-titanium-cloud>`__.
274 The sample input below is for k8s cloud type.
276 **Step 1 - Cloud Registration/ Create a cloud region to represent the instance.**
279 Note: highlighted part of the body refers to an existing OpenStack
280 tenant (OOF in this case). Has nothing to do with the K8s cloud region
285 PUT https://{{AAI1_PUB_IP}}:{{AAI1_PUB_PORT}}/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/k8scloudowner4/k8sregionfour
287 "cloud-owner": "k8scloudowner4",
288 "cloud-region-id": "k8sregionfour",
290 "owner-defined-type": "t1",
291 "cloud-region-version": "1.0",
292 "complex-name": "clli1",
293 "cloud-zone": "CloudZone",
294 "sriov-automation": false,
295 "cloud-extra-info":"{\"openstack-region-id\":\"k8sregionthree\"}",
296 "esr-system-info-list": {
299 "esr-system-info-id": "55f97d59-6cc3-49df-8e69-926565f00066",
300 "service-url": "http://10.12.25.2:5000/v3",
302 "password": "onapdemo",
303 "system-type": "VIM",
304 "ssl-insecure": true,
305 "cloud-domain": "Default",
306 "default-tenant": "OOF",
307 "tenant-id": "6bbd2981b210461dbc8fe846df1a7808",
308 "system-status": "active"
314 **Step 2 add a complex to the cloud**
316 Note: just adding one that exists already
320 PUT https://{{AAI1_PUB_IP}}:{{AAI1_PUB_PORT}}/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/k8scloudowner4/k8sregionfour/relationship-list/relationship
322 "related-to": "complex",
323 "related-link": "/aai/v13/cloud-infrastructure/complexes/complex/clli1",
324 "relationship-data": [
326 "relationship-key": "complex.physical-location-id",
327 "relationship-value": "clli1"
332 **Step 3 - Trigger the Multicloud plugin registration process**
337 POST http://{{MSB_IP}}:{{MSB_PORT}}/api/multicloud-titaniumcloud/v1/k8scloudowner4/k8sregionfour/registry
340 This registers the K8S cloud with Multicloud it also reaches out and
341 adds tenant information to the cloud (see example below you'll see all
342 kinds of flavor, image information that is associated with the OOF
345 If we had not done it this way, then wed have to go in to AAI at this
346 point and manually add a tenant to the cloud region. The first time I
347 tried this (k8s region one), I just made up some random tenant id and
350 The tenant is there so you can add the service-subscription to it:
352 **Making a Service Type:**
356 PUT https://{{AAI1_PUB_IP}}:{{AAI1_PUB_PORT}}/aai/v13/service-design-and-creation/services/service/vfw-k8s
358 "service-description": "vfw-k8s",
359 "service-id": "vfw-k8s"
362 Add subscription to service type to the customer (Demonstration in this
363 case which was already created by running the robot demo scripts)
367 PUT https://{{AAI1_PUB_IP}}:{{AAI1_PUB_PORT}}/aai/v16/business/customers/customer/Demonstration/service-subscriptions/service-subscription/vfw-k8s
369 "service-type": "vfw-k8s"
372 Add Service-Subscription to the tenant (resource-version changes based
373 on actual value at the time):
377 PUT https://{{AAI1_PUB_IP}}:{{AAI1_PUB_PORT}}/aai/v16/cloud-infrastructure/cloud-regions/cloud-region/k8scloudowner4/k8sregionfour/tenants/tenant/6bbd2981b210461dbc8fe846df1a7808?resource-version=1559345527327
379 "tenant-id": "6bbd2981b210461dbc8fe846df1a7808",
380 "tenant-name": "OOF",
381 "resource-version": "1559345527327",
382 "relationship-list": {
385 "related-to": "service-subscription",
386 "relationship-label": "org.onap.relationships.inventory.Uses",
387 "related-link": "/aai/v13/business/customers/customer/Demonstration/service-subscriptions/service-subscription/vfw-k8s",
388 "relationship-data": [
390 "relationship-key": "customer.global-customer-id",
391 "relationship-value": "Demonstration"
394 "relationship-key": "service-subscription.service-type",
395 "relationship-value": "vfw-k8s"
403 **Distribute the CSAR**
404 -----------------------
405 Onboard a service it gets stored in SDC final action is distributed. SO
406 and other services are notified sdc listener in the multicloud sidecar.
407 When distribution happens it takes tar.gz file and uploads to k8s
410 **Create Profile Manually**
411 ---------------------------
413 K8s-plugin artifacts start in the form of Definitions. These are nothing
414 but Helm Charts wrapped with some metadata about the chart itself. Once
415 the Definitions are created, we are ready to create some profiles so
416 that we can customize that definition and instantiate it in Kubernetes.
418 NOTE: Refer this link_ for complete API lists and
421 .. _link : https://wiki.onap.org/display/DW/MultiCloud+K8s-Plugin-service+API
423 A profile consists of the following:
427 - Contains the details for the profile and everything contained within
429 A **HELM** values override yaml file.
431 - It can have any name as long as it matches the corresponding entry in the **manifest.yaml**
433 Any number of files organized in a folder structure
435 - All these files should have a corresponding entry in **manifest.yaml** file
437 **Creating a Profile Artifact**
438 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
442 > cd multicloud-k8s/kud/tests/vnfs/testrb/helm/profile
448 testfol/subdir/deployment.yaml
450 #Create profile tar.gz
452 > tar -cf profile.tar *
454 > mv profile.tar.gz ../
456 The manifest file contains the following
463 values: "values_override.yaml"
465 - filepath: testfol/subdir/deployment.yaml
466 chartpath: vault-consul-dev/templates/deployment.yaml
468 Note: values: "values\_override.yaml" can **be** empty **file** **if**
469 you are creating **a** dummy **profile**
471 Note: A dummy profile does not need any customization. The following is
472 optional in the manifest file.
477 - filepath: testfol/subdir/deployment.yaml
478 chartpath: vault-consul-dev/templates/deployment.yaml
480 We need to read the name of the Definition which was created while distribution of the service from SDC.
482 **Command to read the Definition name and its version**
483 On the ONAP K8s Rancher host execute following statement
487 kubectl logs -n onap `kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}' | grep multicloud-k8s | head -1` -c multicloud-k8s
489 From the output read the name of the definition which is "rb-name" and "rb-version" respectively
493 127.0.0.1 - - [15/Jul/2019:07:56:21 +0000] "POST /v1/rb/definition/test-rbdef/1/content HTTP/1.1"
495 **Command to read (GET) Definition**
497 With this information, we are ready to upload the profile with the
503 "rb-name": "test-rbdef",
505 "profile-name": "p1",
506 "release-name": "r1", //If release-name is not provided, profile-name will be used
507 "namespace": "testnamespace1",
508 "kubernetes-version": "1.13.5"
512 **Command to create (POST) Profile**
513 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
517 curl -i -d @create_rbprofile.json -X POST http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/rb/definition/test-rbdef/1/profile
521 **Command to UPLOAD artifact for Profile**
525 curl -i --data-binary @profile.tar.gz -X POST http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/rb/definition/test-rbdef/1/profile/p1/content
529 **Command to GET Profiles**
533 curl -i http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/rb/definition/test-rbdef/1/profile
535 curl -i http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/rb/definition/test-rbdef/1/profile/p1
539 **Command to DELETE Profile**
542 curl -i -X DELETE http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/rb/definition/test-rbdef/1/profile/p1
548 Instantiation is done by SO. SO then talks to Multi Cloud-broker via MSB
549 and that in turn looks up the cloud region in AAI to find the endpoint.
550 If k8sregion one is registered with AAI and SO makes a call with that,
551 then the broker will know that it needs to talk to k8s-plugin based on
552 the type of the registration.
554 **Instantiate the created Profile via the following REST API**
558 Using the following JSON:
560 "cloud-region": "kud",
561 "profile-name": "p1",
562 "rb-name":"test-rbdef",
568 **NOTE**: Make sure that the namespace is already created before
571 Instantiate the profile with the ID provided above
573 **Command to Instantiate a Profile**
577 curl -d @create_rbinstance.json http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/instance
580 The command returns the following JSON
588 "profile-name": "profile1",
589 "cloud-region": "kud",
590 "namespace": "testns",
611 "Version": "v1beta1",
612 "Kind": "StatefulSet"
614 "Name": "profile1-mongo"
619 **Delete Instantiated Kubernetes resources**
621 The **id** field from the returned JSON can be used to **DELETE** the
622 resources created in the previous step. This executes a Delete operation
623 using the Kubernetes API.
627 curl -X DELETE http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/instance/ZKMTSaxv
630 **GET Instantiated Kubernetes resources**
633 The **id field** from the returned JSON can be used to **GET** the
634 resources created in the previous step. This executes a get operation
635 using the Kubernetes API.
639 curl -X GET http://MSB_NODE_IP:30280/api/multicloud-k8s/v1/v1/instance/ZKMTSaxv
642 `*\ https://github.com/onap/oom/blob/master/kubernetes/multicloud/resources/config/provider-plugin.json <https://github.com/onap/oom/blob/master/kubernetes/multicloud/resources/config/provider-plugin.json>`__
644 **Create User parameters**
646 We need to create parameters that ultimately get translated as:
653 "attribute_name": "definition-name",
654 "attribute_value": "edgex"
657 "attribute_name": "definition-version",
658 "attribute_value": "v1"
661 "attribute_name": "profile-name",
662 "attribute_value": "profile1"