Merge "Terraform Infra-driver for Insta/Termi"

This commit is contained in:
Zuul 2023-07-12 06:20:47 +00:00 committed by Gerrit Code Review
commit c36317e842

View File

@ -0,0 +1,427 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
============================================================
Terraform Infra-driver for VNF Instantiation and Termination
============================================================
This specification describes Terraform Infra-driver in Tacker. The scope of the
present document includes VNF instantiation and termination with this new
infra-driver, using AWS as an example NFVI.
https://blueprints.launchpad.net/tacker/+spec/terraform-infra-driver
Problem description
===================
Tacker is designed as a G-VNFM that supports both VNF and CNF LCM. However,
OpenStack is the only platform where Tacker can deploy VNF among the variety of
cloud platforms. Given the recent multi-cloud trends in cloud computing, Tacker
have to overcome this potential disadvantage by implementing additional
infra-driver.
Proposed change
===============
This spec proposes to support Terraform infra-driver. Terraform [#terraform]_
is the de-facto standard in the IaC area, it's platform-agnostic, declarative
and open source. Using Terraform as a backend tool enables Tacker to create
virtual resources on several platforms that Terraform has already supported,
such as AWS. Terraform has its own configuration language to define virtual
resources, like manifest in Kubernetes or Helm chart in Helm. Users can easily
create VNF packages for Terraform infra-driver by including the configuration.
For this to happen, the following items have to be implemented.
* VNF Instantiation with Terraform Infra-driver
* VNF Termination with Terraform Infra-driver
* Adding DB table/field to store Terraform state (optional)
* Sample VNF packages for Terraform infra-driver
* Updating user document
Terraform
---------
HashiCorp Terraform is an infrastructure as code tool that lets you define both
cloud and on-prem resources in human-readable configuration files that you can
version, reuse, and share. Put simply, you can see Terraform as generic
OpenStack Heat that can be used among several cloud platforms. Terraform
supports a number of cloud infrastructure providers such as:
* Amazon Web Services
* Cloudflare
* Microsoft Azure
* IBM Cloud
* Serverspace
* Google Cloud Platform
* DigitalOcean
* Oracle Cloud Infrastructure
* Yandex.Cloud
* VMware vSphere
* OpenStack
* Kubernetes
* Helm
Terraform uses declarative configuration to describe the desired final state
and its client-side is provided only a CLI tool, similar to Helm. Therefore,
the basic architecture of Terraform infra-driver can be similar to Helm
infra-driver.
The following are the characteristics of Terraform:
#. Configuration file
Terraform has its own language HCL for the resource definition. The files
containing Terraform code are often called configuration files. These files
correspond to the Helm chart in Helm.
#. Variables
Terraform allows users to define variables in configuration files.
Variables can be set as a file or parameters of Terraform CLI. This is a
similar mechanism to the values in Helm.
#. State file and state lock file
Terraform creates a state file and a state lock file [#tf_state]_ when
Terraform creates actual resources. This might be the biggest difference
from Helm. This state file records the information of resources created by
Terraform. The state lock file prevents others from acquiring the lock and
potentially corrupting your state in the case where multiple users manage
the same resources with Terraform in different places.
.. note:: In Kubernetes, the state file corresponds to the resources on
Kubernetes worker nodes which store all information of actual resources
managed by Kubernetes. As there's no entity corresponding to the worker
nodes, Terraform creates state files.
This figure shows the overview of the operation of Terraform, and input/output
files.
.. uml::
@startuml
actor "User" as user
component "Terraform CLI" as cli
component "Terraform" as tf
component "Configuration file" as config
component "Variables file" as vars
component "Target Service" as svc
file "State file" as state
file "State lock file" as statelock
'# Relationships
user --> config: 1. Create Configuration file
user --> vars: 1. Create Variables file
user -> cli
cli -> tf: 2. Init Terraform\n with configuration file\n and variables file
tf --> statelock: 3. Create state lock file
cli -> tf: 4. Apply Configuration file
tf -> svc: 5. Call APIs
tf --> state: 6. Create state file
@enduml
Terraform Infra-driver
----------------------
This figure shows an overview of Instantiate VNF with the Terraform
infra-driver. Terminate VNF is omitted as it is almost the same as the
Instantiate VNF.
Instantiate VNF consist of the following steps:
#. Request create VNF
Users request create VNF with a VNF package that contains Terraform config
and variable files in addition to VNFD.
#. Request instantiate VNF
Users request instantiate VNF with an instantiate parameters that can
overrides variables defined in Terraform variables file.
#. Execute Terraform command
Terraform infra-driver executes terraform command to apply configuration
files to Terraform.
#. Call target service API
Terraform calls target service APIs according to the configuration file.
#. Create VM(s)
Target service (e.g., OpenStack Nova, AWS EC2, etc) creates VM(s).
.. uml::
@startuml
frame "python-tackerclient" {
component "tacker-client" as client {
package "VNF Package" as vnfpkg {
file "VNFD" as vnfd
file "Terraform\nconfiguration" as tffile
file "Terraform\nvariables\nfile" as tfvar
}
file "Instantiate\nparameters" as inst_param
}
}
vnfd -[hidden]> tffile
tffile-[hidden]> tfvar
frame "tacker" {
component "tacker-server" {
component "server" as serv
}
component "tacker-conductor" {
component "conductor" as cond
component "Terraform\ninfra-driver" as infra
}
}
node "Terraform"
node "Target Service" as ts
cloud "Hardware Resources" as hw {
node "VM" as ins1
}
'# Relationships
vnfpkg --> serv: 1. Request\n create VNF
inst_param --> serv: 2. Request\n instantiate VNF
serv --> cond
cond --> infra
infra --> Terraform: 3. Execute Terraform command
Terraform -right-> ts: 4. Call target\n service API
ts --> ins1: 5. Create VM(s)
@enduml
State file management
`````````````````````
Given that terraform config file is located in VNF packages, state files are
created and managed for each VNF instance. Terraform provides several options
(i.e., backend) to store the state file [#tf_state_backend]_. Based on the
available backend, the available options for Tacker are the following:
#. Store state files as a local file
#. Store state files in InstantiatedVnfInfo
#. Store state files in a new DB table/field
#. Store state files in Kubernetes Secret
#. Store state files in PostgresDB
The first option is the easiest way. As Tacker extracts a VNF package into a
local directory, we can place a state file in that local directory. However,
this makes creating more than one VNF instance from one VNF package almost
impossible. Thus, practically, we need to create another directory for each VNF
instance, copy all contents of a VNF package and keep the state file there.
If the first option is not possible, for example, there is no way to create
temporal directories, we can manage the state file on the InstantiatedVnfInfo
field. Since the data type of this field is structure [#sol003]_ and the state
file is written in JSON, we can directly store the state file in that field.
This field is also suitable in the sense that the lifecycle of the state file
matches that of the VNF Instance.
The rest of the options are not recommended as it incurs changes on the data
model of Tacker or requires another component to manage the state file.
This figure shows the basic idea of the first option.
.. uml::
@startuml
left to right direction
component "Terraform infra-driver" as tfid
folder "VNF Package A" as pkga
folder "VNF Package B" as pkgb
folder "Directory for VNF Instance A" as da {
file "Configuration" as ca
file "Variables" as va
file "State file A" as statea
file "State lock file A" as statelocka
}
folder "Directory for VNF Instance B" as db {
file "Configuration" as cb
file "Variables" as vb
file "State lock file B" as statelockb
file "State file B" as stateb
}
folder "Directory for VNF Instance C" as dc {
file "Configuration" as cc
file "Variables" as vc
file "State lock file C" as statelockc
file "State file C" as statec
}
dc -[hidden]> db
db -[hidden]> da
component "Terraform" as tf
'# Relationships
tfid -> tf: Execute
tfid <-up- pkga: Download
tfid <-up- pkgb: Download
tfid ---> da: Copy VNF Package A
tfid ---> db: Copy VNF Package A
tfid ---> dc: Copy VNF Package B
tf --> statea: Create
tf --> statelocka: Create
tf --> stateb: Create
tf --> statelockb: Create
tf --> statec: Create
tf --> statelockc: Create
@enduml
State lock file management
``````````````````````````
Ideally, we can disable generating state lock files [#tf_lock]_ as Tacker is
only the entity that manages the resources associated with the instantiated
VNF. If we need to use the lock file, we have the similar options as the state
file as follows:
#. Store state files as a local file
#. Store state files in InstantiatedVnfInfo
#. Store state files in a new DB table/field
Alternatives
------------
Implementing infra-driver for individual platform can be an alternative.
Data model impact
-----------------
None. One possible reason for data model changes is to make new table/field to
store state and state lock files. As described in the State file management
section, we have several alternative ways.
REST API impact
---------------
None.
Security impact
---------------
Terraform uses sensitive data in some scenes. For example, Terraform requires
credentials to make API requests. In general, we can avoid exposure of
sensitive data by using environment variables. However, at the same time, we
need to carefully make configuration files.
Potential risks are listed as follows, but there can be more:
* Hardcoded credentials for the target services
* Hardcoded credentials for the backend of the state file [#tf_state_sec]_
See the best practice for details [#tf_sec]_
Notifications impact
--------------------
None. However, if state files are stored in InstantiatedVnfInfo, they can be
omitted from LcmOpOccNotification.
Other end user impact
---------------------
None.
Performance Impact
------------------
None. Terraform itself and the state file (might be located on DB) might use
storage, but it is negligibly small. As the infra-drivers are abstracted by
Tacker's VNF LCM driver, Terraform infra-driver does not affect to the overall
performance.
Other deployer impact
---------------------
After merging this feature, the following points must be considered:
* Users need to install Terraform when using Terraform infra-driver
* Tacker community should add installation of Terraform in Zuul to tests
Terraform infra-driver
No effects on existing deployments as this is a new feature independent of the
existing ones.
Developer impact
----------------
* Developers may need to update Terraform infra-driver according to the update
of Terraform.
* Developers may need to fix bugs of Terraform infra-driver caused by the
Terraform.
* Developers may need to be careful to change other components than Terraform
infra-driver, such as VNF package format, controllers, conductor, etc, so
that it works in Terraform infra-driver.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
* Hiromu Asahina (hiromu) <hiromu.asahina@ntt.com> <hiromu.a5a@gmail.com>
Other contributors:
* TBD
Work Items
----------
* VNF Instantiation with Terraform Infra-driver
* VNF Termination with Terraform Infra-driver
* Adding DB table/field to store Terraform state (optional)
* Sample VNF packages for Terraform infra-driver
* Updating user document
Dependencies
============
* Terraform v1.4.0 or later
Testing
=======
Terraform supports several providers including OpenStack [#tf_os]_, Kubernetes
[#tf_k8s]_, Docker [#tf_local]_ and local files [#tf_docker]_. The easiest way
is to use OpenStack in the functional tests. As terraform infra-driver is
transparent for VNF packages, its normality must not be affected by the
difference of used providers. In this sense, we can test its normality with
other available providers, such as Kubernetes, docker or local provider.
Alternatively, we can use LocalStack [#localstack]_ that acts as a stub of AWS
services.
Documentation Impact
====================
Need to explain the use cases of Terraform infra-driver.
References
==========
.. [#terraform] https://www.terraform.io/
.. [#tf_state] https://developer.hashicorp.com/terraform/language/state
.. [#tf_state_backend] https://developer.hashicorp.com/terraform/language/settings/backends/configuration#available-backends
.. [#sol003] https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/003/03.05.01_60/gs_NFV-SOL003v030501p.pdf
.. [#tf_lock] https://developer.hashicorp.com/terraform/language/state/locking
.. [#tf_os] https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest
.. [#tf_k8s] https://registry.terraform.io/providers/hashicorp/kubernetes/latest
.. [#tf_docker] https://registry.terraform.io/providers/kreuzwerker/docker/latest
.. [#tf_local] https://registry.terraform.io/providers/hashicorp/local/latest
.. [#tf_state_sec] https://developer.hashicorp.com/terraform/language/settings/backends/configuration#credentials-and-sensitive-data
.. [#tf_sec] https://cycode.com/7-terraform-security-best-practices/
.. [#localstack] https://localstack.cloud/