J'utilise packer avec ansible Provider pour construire une AMI et terraform pour configurer l'infrastructure avec cette AMI comme source - un peu similaire à cet article: http://www.paulstack.co.uk/blog/2016/ 01/02/bâtiment-an-elasticsearch-cluster-in-aws-with-packer-and-terraform
Lorsque la commande packer build pack.json
se termine avec succès, j'obtiens l'ID de sortie de l'AMI au format suivant:
eu-central-1: AMI-12345678
Dans mes variables terraform variables.tf
, je dois spécifier l'identifiant AMI source, la région, etc. Le problème ici est que je ne souhaite pas les spécifier manuellement ni plusieurs fois. Pour la région (que je connais à l’avance), c’est simple puisque je peux utiliser des variables d’environnement dans les deux situations, mais qu’en est-il de la sortie? Existe-t-il un moyen intégré de chaîner ces produits ou une approche moins astucieuse pour le faire?
EDIT: Approche féroce pour tous ceux qui pourraient être intéressés. Dans cette solution, je grep
ing la région aws et l'AMI de la sortie du programme de compression et j'utilise une expression régulière en Perl pour écrire le résultat dans un fichier terraform.tfvars
:
vars=$(pwd)"/terraform.tfvars"
packer build pack.json | \
tee /dev/tty | \
grep -E -o '\w{2}-\w+-\w{1}: AMI-\w+' | \
Perl -ne '@parts = split /[:,\s]+/, $_; print "aws_amis." . $parts[0] ." = \"" . $parts[1] . "\"\n"' > ${vars}
Vous devriez envisager d'utiliser la source Data Source de aws_AMI
de Terraform. Avec cela, vous pouvez compter sur les balises personnalisées que vous définissez sur l'AMI lors de sa création (par exemple, un numéro de version ou un horodatage). Ensuite, dans la configuration Terraform, vous pouvez simplement filtrer les AMI disponibles pour ce compte et cette région afin d'obtenir l'ID AMI dont vous avez besoin.
https://www.terraform.io/docs/providers/aws/d/AMI.html
data "aws_AMI" "nat_AMI" {
most_recent = true
executable_users = ["self"]
filter {
name = "owner-alias"
values = ["Amazon"]
}
filter {
name = "name"
values = ["amzn-AMI-vpc-nat*"]
}
name_regex = "^myami-\\d{3}"
owners = ["self"]
}
REMARQUE: dans l'exemple ci-dessus (tiré de la documentation), la combinaison de filtres est probablement excessive. Vous pouvez probablement vous en tirer très bien avec quelque chose comme:
data "aws_AMI" "image" {
most_recent = true
owners = ["self"]
filter {
name = "tag:Application"
values = ["my-app-name"]
}
}
output "AMI_id" {
value = "${data.aws_AMI.image.id}"
}
Un avantage supplémentaire de cela est que vous pouvez déployer dans plusieurs régions avec la même configuration et sans carte variable!
La méthode "officielle" recommandée par Hashicorp consiste à utiliser son produit Atlas comme "intermédiaire" entre les deux. Vous utiliseriez le post-processeur Atlas dans Packer pour enregistrer les artefacts (identificateurs AMI, dans votre cas), puis utiliser la ressource atlas_artifact
dans Terraform pour relire les identifiants. pour une utilisation dans Terraform.
Dans ce cas, vous obtiendrez les identifiants de la ressource plutôt que de les transmettre à l'aide de variables.
Mis à part Atlas, les autres options sont plutôt limitées et, dans certains cas, hacky.
Si vous voulez le faire sans aucun service externe, vous pouvez essayer le post-processeur local Shell comme moyen d’exécuter une commande locale sur votre artefact, ou vous pouvez utiliser la machine. -leadable output pour extraire les identifiants AMI et les écrire dans un fichier de variables pour Terraform.
Une autre option consiste à écrire votre propre plug-in post-processeur qui interagit avec certains logiciels que vous utilisez déjà, au lieu d’Atlas. Par exemple, avec certains de mes collègues, j’ai écrit un post-processeur pour enregistrer les artefacts sous forme de métadonnées dans Buildkite , que nous avons ensuite récupérés à l’aide de la Buildkite API . Cela nécessite l'écriture de code personnalisé dans Go.
Au moment de la rédaction de ce manuel, la version 0.7 de Terraform était encore en développement, mais il est prévu d'inclure une nouvelle fonctionnalité permettant d'interroger directement l'API EC2 pour les AMI, ce qui (s'il atterrit effectivement à 0.7) permet une option supplémentaire de marquage de l'AMI avec Packer et ensuite le trouver directement à partir de EC2 en utilisant ces balises. Cela utilise EC2 lui-même comme "intermédiaire", ce qui est peut-être moins gênant puisqu'il a déjà été utilisé comme mémoire pour l'AMI.
C'est l'approche que j'ai utilisée:
Il est similaire à la version de la réponse modifiée. Plus en détail, cela peut ressembler à ceci:
Commencez par créer un fichier appelé AMI.tf.template
:
# "AMI.tf" was automatically generated from the template "AMI.tf.template".
variable "AMI" {
default = "${AMI_GENERATED_BY_PACKER}"
description = "The latest AMI."
}
Ce modèle sera utilisé pour créer le fichier AMI.tf
, ce qui rend l’AMI de l’emballeur disponible pour votre configuration Terraform existante.
Deuxièmement, créez un script d'encapsulation Shell pour l'exécution du programme de compression. Vous pouvez utiliser les idées suivantes:
# run packer (prints to stdout, but stores the output in a variable)
packer_out=$(packer build packer.json | tee /dev/tty)
# packer prints the id of the generated AMI in its last line
AMI=$(echo "$packer_out" | tail -c 30 | Perl -n -e'/: (AMI-.+)$/ && print $1')
# create the 'AMI.tf' file from the template:
export AMI_GENERATED_BY_PACKER="$AMI" && envsubst < AMI.tf.template > AMI.tf
Une fois le script terminé, il a créé un fichier AMI.tf
, qui peut ressembler à ceci:
# "AMI.tf" was automatically generated from the template "AMI.tf.template".
variable "AMI" {
default = "AMI-aa92a441"
description = "The latest AMI."
}
Enfin, placez ce fichier à côté de votre configuration Terraform existante. Ensuite, vous pouvez accéder à l’AMI comme ceci:
resource "aws_launch_configuration" "foo" {
image_id = "${var.AMI}"
...
}