Dein eigener Provider
Ein kurzes Howto, wie sie einen eignene Terraform Provider schreiben können.
Was sind Terraform-Provider?
Das Erstellen und Verwalten von Ressourcen mit Terraform basiert auf Plug-ins, die als Provider bezeichnet werden. Jedes Provider-Plug-In ist für die Interaktion mit Cloud-Providern, SaaS-Providern und anderen APIs verantwortlich. Die meisten Provider konfigurieren eine bestimmte Infrastrukturplattform (entweder in der Cloud oder selbst gehostet). Provider können auch lokale Dienstprogramme für Aufgaben wie das Generieren von Zufallszahlen für eindeutige Ressourcennamen anbieten.
Jeder Provider fügt eine Reihe von Ressourcentypen und/oder Datenquellen hinzu, die Terraform verwalten kann. Jeder Ressourcentyp wird von einem Provider implementiert; Ohne Provider kann Terraform keinerlei Infrastruktur verwalten. Terraform Provider ermöglicht Erweiterbarkeit nicht nur für die Cloud-Infrastruktur, sondern ermöglicht auch die Verwaltung von Objekten, die durch offengelegte API-Aufrufe erstellt werden können.
Benutzerdefinierter Terraform-Provider
Im Folgenden sind einige der möglichen Szenarien zum Erstellen eines benutzerdefinierten Terraform-Providers aufgeführt, z. B.:
Eine interne Private Cloud, deren Funktionalität entweder proprietär ist oder der Open-Source-Community keinen Nutzen bringen würde.
Ein in Arbeit befindlicher Provider, der lokal getestet wird, bevor er zur Registrierung beiträgt.
Erweiterungen eines bestehenden Providers.
Wie funktioniert das Terraform- und Provider-Plug-in?
Gemäß der Terraform-Dokumentation :
Terraform-Core
Terraform Core ist eine statisch kompilierte Binärdatei, die in der Programmiersprache Go geschrieben wurde. Die kompilierte Binärdatei ist das Befehlszeilentool (CLI) terraform, und dies ist der Einstiegspunkt für jeden, der Terraform verwendet.
Die Hauptaufgaben von Terraform Core sind:
Infrastruktur als Code: Lesen und Interpolieren von Konfigurationsdateien und Modulen
Verwaltung des Ressourcenzustands
Konstruktion des Ressourcengraphen
Ausführung planen
Kommunikation mit Plugins über RPC
Terraform-Plugins
Terraform-Plugins werden in Go geschrieben und sind ausführbare Binärdateien, die von Terraform Core über RPC aufgerufen werden.
Terraform-Provider-Plug-in-Design Quelle: Terraform-Dokumentation
Jedes Plug-in stellt eine Implementierung für einen bestimmten Dienst bereit, z. B. AWS, oder einen Provider wie bash. Alle Provider und Provisioner, die in Terraform-Konfigurationen verwendet werden, werden als Plugins bezeichnet. Terraform Core bietet ein High-Level-Framework, das die Details der Plugin-Erkennung und RPC-Kommunikation abstrahiert, sodass Entwickler sie nicht verwalten müssen.
Die Hauptaufgaben von Provider-Plugins sind:
Initialisierung aller enthaltenen Bibliotheken, die zum Ausführen von API-Aufrufen verwendet werden.
Authentifizierung beim InfrastrukturProvider.
Definieren Sie Ressourcen, die bestimmten Diensten zugeordnet sind
Die Hauptaufgaben von Provisioner-Plug-ins sind:
Ausführen von Befehlen oder Skripten auf der angegebenen Ressource nach der Erstellung oder bei der Zerstörung.
Bitte beachten Sie, dass sich unser Beitrag auf die Entwicklung von Provider-Plugins konzentriert
Installation der Terraform-CLI-Datei und des Provider-Plugins
Terraform 0.13+ verwendet die .terraformrcCLI-Konfigurationsdatei, um das Installationsverhalten des Providers zu handhaben. Also müssen wir die Konfigurationsdatei unter dem Pfad erstellen $HOME/.terraformrcund den folgenden Inhalt hinzufügen:
plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"
disable_checkpoint = true
Für die Provider-Installation stehen zwei Methoden zur Verfügung (ab Terraform 0.13+).
Explizite Installationsmethode
Ein provider_installationBlock in der CLI-Konfiguration ermöglicht das Überschreiben des standardmäßigen Installationsverhaltens von Terraform, sodass Sie Terraform zwingen können, einen lokalen Spiegel für einige oder alle Provider zu verwenden, die Sie verwenden möchten. Bei der expliziten Installationsmethode benötigen wir einen provider_installationBlock.
Implizite lokale Mirror-Methode
Wenn die CLI-Konfigurationsdatei keinen provider_installation Block enthält, erstellt Terraform eine implizite Konfiguration.
Wir werden die implizite lokale Spiegelungsmethode verwenden, um unseren benutzerdefinierten Provider zu installieren.
Das Standardverhalten von terraform initist normalerweise der Versuch, den Provider aus der Terraform-Registrierung aus dem Internet herunterzuladen. Da wir das benutzerdefinierte Providerszenario nachahmen,
können wir dieses Verhalten durch eine implizite Methode überschreiben. Mit der impliziten Methode versucht Terraform implizit, die Provider lokal im Plugin-Verzeichnis ~/.terraform.d/plugins
für Linux-Systeme
und %APPDATA%\terraform.d\plugins
in Windows-Systemen zu finden.
Was ist erforderlich, um einen benutzerdefinierten Provider zu entwickeln?
Nur ein grundlegendes Go-Entwicklungswissen reicht aus, um loszulegen.
Offengelegte API-Details vom DienstProvider zum Verwalten von Ressourcen.
So installieren und konfigurieren Sie Terraform
Informationen zur Installation von Terraform finden Sie hier
Fenster:
Laden Sie die ausführbare Terraform-Datei herunter und extrahieren Sie sie
Fügen Sie den ausführbaren Terraform-Pfad zur Variablen ENV PATH hinzu
Extrahieren und kopieren Sie in Linux-Varianten die ausführbare Terraform-Datei in den Pfad /usr/bin, um sie von einem beliebigen Verzeichnis aus auszuführen. Installieren Sie Go und richten Sie die Entwicklungsumgebung ein
Befolgen Sie die Installationsschritte für Go, die auf der offiziellen Go-Website erwähnt werden , und beginnen Sie mit Go.
Details zum Quellcode des benutzerdefinierten Providers
Gehen Sie zu $HOME/go/src
Pfad und erstellen Sie Code.
cd $HOME/go/src
mkdir tf_custom_provider
Erforderliche Quelldateien für benutzerdefinierte Provider sind:
main.go
provider.go
resource_server.go
Das Code-Layout sieht so aus:
.
├── main.go
├── provider.go
├── resource_server.go
Funktionalität des Providers
Wir werden einen Provider mit der folgenden Funktionalität erstellen. Da dies ein Beispiel sein wird, werden wir die Funktionen zum Erstellen und Löschen von Terraform-Ressourcen verspotten. Wir werden auch die Zufalls-UUID-Generator-API verwenden und sie wird als Teil der Erstellungsfunktion hinzugefügt, um die Möglichkeit zum Aufrufen des API-Aufrufs zu zeigen. Die API kann später mit der tatsächlichen Ressourcenerstellungs-API für Cloud-Provider, On-Prem-DienstProvider oder eine beliebige As a ServiceProvider-API geändert werden.
main.go
Go-Einstiegspunktfunktion ist main.go
.
// main.go
package main
import (
"github.com/hashicorp/terraform-plugin-sdk/plugin"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
)
func main() {
plugin.Serve(&plugin.ServeOpts{
ProviderFunc: func() terraform.ResourceProvider {
return Provider()
},
})
}
Provider.go
provider.go
wird die Ressourcen-Server-Funktionsaufrufe haben.
// provider.go
package main
import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
func Provider() *schema.Provider {
return &schema.Provider{
ResourcesMap: map[string]*schema.Resource{
"example_server": resourceServer(),
},
}
}
resource_server.go
Die gesamte Ressourcenerstellung muss in codiert werden resource_server.go
. Diese Datei enthält die Ressourcenfunktionsdeklaration und -definition wie Erstellen, Löschen usw. Sie erhält auch die Eingabeparameter,
die zum Erstellen von Ressourcen erforderlich sind.
Als Teil dieses BeispielProviders verfügt der Ressourcenserver über die folgenden Funktionen:
apply
delete
// resource_server.go
package main
import (
"net/http"
"log"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
func resourceServer() *schema.Resource {
return &schema.Resource{
Create: resourceServerCreate,
Read: resourceServerRead,
Update: resourceServerUpdate,
Delete: resourceServerDelete,
Schema: map[string]*schema.Schema{
"uuid_count": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
},
}
}
func resourceServerCreate(d *schema.ResourceData, m interface{}) error {
uuid_count := d.Get("uuid_count").(string)
d.SetId(uuid_count)
// https://www.uuidtools.com/api/generate/v1/count/uuid_count
resp, err := http.Get("https://www.uuidtools.com/api/generate/v1/count/" + uuid_count)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
return resourceServerRead(d, m)
}
func resourceServerRead(d *schema.ResourceData, m interface{}) error {
return nil
}
func resourceServerUpdate(d *schema.ResourceData, m interface{}) error {
return resourceServerRead(d, m)
}
func resourceServerDelete(d *schema.ResourceData, m interface{}) error {
d.SetId("")
return nil
}
Unser Beispielcode implementiert die Mock-Ressourcenerstellung für den Provider namens „exampleprovider“. In einer tatsächlichen Implementierung muss es für den Providernamen des jeweiligen Cloud- oder On-Premises-Servers geändert werden. Die meisten Provider haben API-Aufrufe, die für Ressourcenoperationen wie Erstellen/Aktualisieren/Löschen usw. verwendet werden. Daher müssen wir die Logik von Ressourcenoperationen wie Erstellen und Löschen mithilfe der benutzerdefinierten Provider-API-Aufrufe definieren, um die Terraform-Vorlage anzuwenden.
Nachdem Sie die Logik für Ressourcenvorgänge in hinzugefügt haben resource_server.go
, kann unser benutzerdefinierter Provider getestet werden.
Erstellen Sie den benutzerdefinierten Providercode
go mod init
go fmt go mod tidy
go build -o terraform-provider-example
Schritte zum Kopieren der ausführbaren Providerdatei in das Plug-in-Verzeichnis
Um den von uns erstellten benutzerdefinierten Provider zu kopieren und zu verwenden, müssen wir die folgende Verzeichnisstruktur im Plug-in-Verzeichnis erstellen:
Linux-basiertes System -~/.terraform.d/plugins/${host_name}/${namespace}/${type}/${version}/${target}
Windows-basiertes System%APPDATA%\terraform.d\plugins\${host_name}/${namespace}/${type}/${version}/${target}
Wo:
host_name-> irgendeinhostname.com
namespace-> Namensraum des benutzerdefinierten Providers
Typ-> Benutzerdefinierter Providertyp
Version-> semantische Versionierung des Providers (Bsp.: 1.0.0)
Ziel -> Zielbetriebssystem
Unser benutzerdefinierter Provider sollte wie folgt in das Verzeichnis aufgenommen werden:
~/.terraform.d/plugins/terraform-example.com/exampleprovider/example/1.0.0/linux_amd64/terraform-provider-example
Als ersten Schritt müssen wir also das Verzeichnis als Teil unserer Provider-Installation erstellen:
mkdir -p ~/.terraform.d/plugins/terraform-example.com/exampleprovider/example/1.0.0/linux_amd64
Kopieren Sie dann die terraform-provider-exampleBinärdatei an diesen Ort:
cp terraform-provider-example ~/.terraform.d/plugins/terraform-example.com/exampleprovider/example/1.0.0/linux_amd64
Erstellen Sie Terraform- .tf Dateien
Lassen Sie uns den Provider testen , indem wir main.tf, indem wir die Ressourceneingaben bereitstellen, erstellen. Wir haben die Anzahl der Serverzähler ( uuid_count) als Eingabeparameter für Demozwecke hinzugefügt.
main.tf
Erstellen Sie main.tfeine Datei mit Code, um eine benutzerdefinierte Providerressource zu erstellen:
resource "example_server" "my-server-name" {
uuid_count = "1"
}
version.tf
Erstellen Sie eine Datei mit dem Namen versions.tfund fügen Sie den Pfad zum Namen und zur Version des benutzerdefinierten Providers hinzu:
terraform {
required_providers {
example = {
version = "~> 1.0.0"
source = "terraform-example.com/exampleprovider/example"
}
}
}
Testen Sie den Provider und geben Sie Werte aus
Führen Sie die folgenden Terraform-Befehle aus, um die von uns hinzugefügten benutzerdefinierten Providerfunktionen zu überprüfen. Terraform-Initialisierung
Wenn wir terraform initden Befehl ausführen, ruft der Terraform-Kern das Provider-Plugin aus dem lokalen Pfad ab, da wir den Provider in der versions.tfDatei konfiguriert haben.
Während der Terraform-Initialisierung wurde der benutzerdefinierte Provider im ~/.terraform.d/plugin-cache
Verzeichnis zwischengespeichert, um den Provider bei der nächsten Ausführung wiederzuverwenden.
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding terraform-example.com/exampleprovider/example versions matching "~> 1.0.0"...
- Using terraform-example.com/exampleprovider/example v1.0.0 from the shared cache directory
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# example_server.my-server-name will be created
+ resource "example_server" "my-server-name" {
+ id = (known after apply)
+ uuid_count = "1"
}
Plan: 1 to add, 0 to change, 0 to destroy.
$ terraform apply
Terraform will perform the following actions:
# example_server.my-server-name will be created
+ resource "example_server" "my-server-name" {
+ id = (known after apply)
+ uuid_count = "1"
}
Plan: 1 to add, 0 to change, 0 to destroy.
example_server.my-server-name: Creating...
example_server.my-server-name: Creation complete after 0s [id=1]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Aufräumen
$ terraform destroy
Terraform will perform the following actions:
# example_server.my-server-name will be destroyed
- resource "example_server" "my-server-name" {
- id = "1" -> null
- uuid_count = "1" -> null
}
Plan: 0 to add, 0 to change, 1 to destroy.
example_server.my-server-name: Destroying... [id=1]
example_server.my-server-name: Destruction complete after 0s
Destroy complete! Resources: 1 destroyed.
Fazit
In diesem technischen Blogbeitrag haben wir die folgenden Themen behandelt:
Funktionsweise des Terraform-Providers.
Was ist ein benutzerdefinierter Terraform-Provider?
Schritte zum Erstellen und Erstellen eines Beispiel-Terraform-Providers.
Schritte zur Verwendung des benutzerdefinierten Providers.
Was beim Aufrufen der Terraform-CLI-Befehle passiert.