Используйте предварительно установленные плагины Terraform вместо загрузки их с помощью terraform init

Во время бега terraform init при использовании Terraform 0.11.3 мы получаем следующую ошибку:

Инициализация плагинов провайдера... - Проверка доступных плагинов провайдера на https://releases.hashicorp.com/...

Ошибка при установке "шаблона" провайдера: получите https://releases.hashicorp.com/terraform-provider-template/: прочитайте tcp 172.25.77.25:53742->151.101.13.183:443: прочитайте: сброс соединения по одноранговому узлу.

Terraform анализирует конфигурацию и состояние и автоматически загружает плагины для используемых провайдеров. Однако при попытке загрузить этот плагин произошла непредвиденная ошибка.

Это может быть вызвано тем, что по какой-то причине Terraform не может связаться с хранилищем плагинов. Хранилище может быть недоступно, если доступ заблокирован брандмауэром.

Если автоматическая установка невозможна или нежелательна в вашей среде, вы можете установить плагины вручную, загрузив подходящий дистрибутив и поместив исполняемый файл плагина в следующую директорию: terraform.d/plugins/linux_amd64

Я понял, что это связано с проблемами соединения с доменом https://releases.hashicorp.com/. По некоторым очевидным причинам нам придется исправить эту проблему с подключением, поскольку между сервером управления и серверами Hashicorp существуют некоторые проблемы с SSL и брандмауэром.

Можно ли как-то обойти это, загрузив плагины с серверов Hashicorp и скопировав их на сервер управления? Или какой-нибудь другой альтернативой, чтобы избежать попыток загрузки вещей с серверов Hashicorp?

7 ответов

Решение

Вы можете использовать предварительно установленные плагины, поместив плагины в тот же каталог, что и terraform бинарный или установив -plugin-dir флаг.

Также возможно автоматически создать пакет из каждого необходимого вам поставщика, используя terraform-bundle инструмент

Я запускаю Terraform в нашем конвейере CI в контейнере Docker, поэтому Dockerfile выглядит примерно так:

FROM golang:alpine AS terraform-bundler-build

RUN apk --no-cache add git unzip && \
    go get -d -v github.com/hashicorp/terraform && \
    go install ./src/github.com/hashicorp/terraform/tools/terraform-bundle

COPY terraform-bundle.hcl .

RUN terraform-bundle package terraform-bundle.hcl && \
    mkdir -p terraform-bundle && \
    unzip -d terraform-bundle terraform_*.zip

####################

FROM python:alpine

RUN apk add --no-cache git make && \
    pip install awscli

COPY --from=terraform-bundler-build /go/terraform-bundle/* /usr/local/bin/

Обратите внимание, что готовое изображение контейнера также добавляет git, make и интерфейс командной строки AWS, поскольку мне также требуются те инструменты в заданиях CI, которые используют этот контейнер.

terraform-bundle.hcl то выглядит примерно так (взято из terraform-bundle ПРОЧИТАЙТЕ):

terraform {
  # Version of Terraform to include in the bundle. An exact version number
  # is required.
  version = "0.10.0"
}

# Define which provider plugins are to be included
providers {
  # Include the newest "aws" provider version in the 1.0 series.
  aws = ["~> 1.0"]

  # Include both the newest 1.0 and 2.0 versions of the "google" provider.
  # Each item in these lists allows a distinct version to be added. If the
  # two expressions match different versions then _both_ are included in
  # the bundle archive.
  google = ["~> 1.0", "~> 2.0"]

  # Include a custom plugin to the bundle. Will search for the plugin in the 
  # plugins directory, and package it with the bundle archive. Plugin must have
  # a name of the form: terraform-provider-*, and must be build with the operating
  # system and architecture that terraform enterprise is running, e.g. linux and amd64
  customplugin = ["0.1"]
}

Правильный способ справиться с этим, начиная с terraform 0.14, как также обсуждалось на странице terraform-bundle, упомянутой в принятом в настоящее время ответе, заключается в использовании terraform providers mirrorкак описано на https://www.terraform.io/cli/commands/providers/mirror . Эта команда создает все необходимые индексные файлы и т. д., чтобы папку можно было использовать для плагинов. Например:

      $ cd your-tf-root-module
$ terraform providers mirror path/to/tf-plugins
...
$ terraform init --plugin-dir path/to/tf-plugins
...

Вы можете cd для каждого из ваших корневых модулей (т.е. тех, у которых есть состояние терраформирования) и запустить команду зеркала; там может быть установлено несколько версий плагина, и это нормально. Когда вы запустите команду инициализации terraform, она выберет правильный вариант. То же, что и без аргумента --plugin-dir.

Таким образом, единственное отличие состоит в том, что для получения плагинов не используется Интернет, terraform init получает их из папки плагинов.

Это также очень полезно для создания кеша, который затем может использоваться terraform в ci/cd. Например, в Circleci у вас будет ручная работа, которая вызывает зеркало и выполняет кэширование; и ваша автоматизированная задача инициализации терраформирования восстановит кеш и использует --plugin-dir arg; тогда автоматизированное задание terraform apply будет вести себя как обычно.

Config plugin_cache_dir в .terraformrc

plugin_cache_dir   = "$HOME/.terraform.d/plugin-cache"

затем переместите предварительно установленный провайдер в plugin_cache_dir,

terraform больше не будет скачивать провайдера

кстати, использовать каталог ~/.terraform.d/plugin не работает

/.terraform.d/plugin/linux_amd64$ terraform -v
Terraform v0.12.15

Начиная с версии 0.13.2 Terraform, можно было загружать плагины с локального веб-сервера /http-сервера через протокол сетевого зеркала.

Для получения дополнительной информации проверьте эту ссылку

Ожидается .terraformrcфайл в пути $HOME, указывая на путь поставщика плагинов, как показано ниже. Если файл находится в другом каталоге, вы можете указать путь с помощью TERRAFORM_CONFIG env var.

provider_installation {
  network_mirror {
    url    = "https://terraform-plugins.example.net/providers/"
  }
}

Затем вы определяете поставщиков в настраиваемом tf, как показано ниже.

Provider.tf::

terraform {
  required_providers {
    azurerm = {
      source  = "registry.terraform.io/example/azurerm"
    }
    openstack = {
      source  = "registry.terraform.io/example/openstack"
    }
    null = {
      source  = "registry.terraform.io/example/null"
    }
    random = {
      source  = "registry.terraform.io/example/random"
    }
    local = {
      source  = "registry.terraform.io/example/local"
    }
  }
}

Однако вы должны загрузить файл плагина в .zip формат вместе с index.json и <version>.json файлы для terraform, чтобы узнать версию загружаемого плагина.

Пример index.json, содержащий версию плагина::

{
  "versions": {
    "2.3.0": {}
  }
}

Опять же, 2.3.0.json содержит хеши файла плагина. В данном случае это <version>.json

{
  "archives": {
    "linux_amd64": {
      "hashes": [
        "h1:nFL6uiwsQFLiP8QCr35sPfWe9LpXI3/c7gP9tYnih+k="
      ],
      "url": "terraform-provider-random_2.3.0_linux_amd64.zip"
    }
  }
}

Как получить подробную информацию о index.json и <version>.json файлы?

Запустив terraform providersв каталоге, содержащем tf-файлы. Обратите внимание: компьютер, на котором выполняется эта команда, должен подключиться к общедоступному реестру terraform. Terraform загрузит информацию об этих файлах. Если у вас разные файлы конфигурации terraform, имеет смысл автоматизировать эти шаги, иначе вы можете сделать это вручную:)

По, terraform init, terraform загружает плагины с указанного выше веб-сервера, а не из реестра terraform. Убедитесь, что вы не используете plugin-dir аргумент с terraform init так как он отменяет все сделанные вами изменения.

Вы можете использовать предустановленные плагины, поместив двоичные файлы плагинов в тот же каталог, где доступен двоичный файл Terraform, установив флаг «plugins-dir».

По умолчанию все плагины загружаются в папку .terraform. Например, плагин нулевого ресурса будет доступен по адресу ниже

.terraform \ Provider \ registry.terraform.io \ hashicorp \ null \ 3.0.0. \ windows_amd64.

Создайте новую папку типа «terraform-plugins» внутри каталога Terraform и скопируйте все содержимое, включая папку registry.terraform.io, упомянутую в приведенном выше примере, в созданную папку.

Теперь запустите команду инициализации terraform с флагом plugins-dir.

terraform init -plugin-dir = "/ terraform-plugins"

укажите полный путь к каталогу с флагом plugin-dir

Это заняло у меня некоторое время, была та же проблема. В итоге мне пришлось скачать из источника и использовать изображение, которое это выплевывает. Это неприятно, но он делает то, что мне нужно, для работы с поставщиком Google.

FROM golang:alpine AS terraform-bundler-build

ENV TERRAFORM_VERSION=0.12.20
ENV GOOGLE_PROVIDER=3.5.0

RUN apk add --update --no-cache git make tree bash curl
ENV GOPATH=/go
RUN mkdir -p $GOPATH/src/github.com/terraform-providers

RUN cd $GOPATH/src/github.com/terraform-providers && curl -sLO https://github.com/terraform-providers/terraform-provider-google-beta/archive/v$GOOGLE_PROVIDER.tar.gz
RUN cd $GOPATH/src/github.com/terraform-providers && tar xvzf v$GOOGLE_PROVIDER.tar.gz && mv terraform-provider-google-beta-$GOOGLE_PROVIDER terraform-provider-google-beta
RUN cd $GOPATH/src/github.com/terraform-providers/terraform-provider-google-beta && pwd &&  make build

RUN cd $GOPATH/src/github.com/terraform-providers && curl -sLO https://github.com/terraform-providers/terraform-provider-google/archive/v$GOOGLE_PROVIDER.tar.gz
RUN cd $GOPATH/src/github.com/terraform-providers && tar xvzf v$GOOGLE_PROVIDER.tar.gz && mv terraform-provider-google-$GOOGLE_PROVIDER terraform-provider-google
RUN cd $GOPATH/src/github.com/terraform-providers/terraform-provider-google && pwd &&  make build

RUN mkdir -p $GOPATH/src/github.com/hashicorp
RUN cd $GOPATH/src/github.com/hashicorp && curl -sLO https://github.com/hashicorp/terraform/archive/v$TERRAFORM_VERSION.tar.gz
RUN cd $GOPATH/src/github.com/hashicorp && tar xvzf v$TERRAFORM_VERSION.tar.gz && mv terraform-$TERRAFORM_VERSION terraform
RUN cd $GOPATH/src/github.com/hashicorp/terraform && go install ./tools/terraform-bundle
ENV TF_DEV=false
ENV TF_RELEASE=true
COPY my-build.sh $GOPATH/src/github.com/hashicorp/terraform/scripts/
RUN cd $GOPATH/src/github.com/hashicorp/terraform && /bin/bash scripts/my-build.sh
ENV HOME=/root
COPY terraformrc $HOME/.terraformrc
RUN mkdir -p $HOME/.terraform.d/plugin-cache

########################################
FROM alpine:3
ENV HOME=/root

RUN ["/bin/sh", "-c", "apk add --update --no-cache bash ca-certificates curl git jq openssh"]

RUN ["bin/sh", "-c", "mkdir -p /src"]
COPY --from=terraform-bundler-build /go/bin/terraform* /bin/
RUN mkdir -p /root/.terraform.d/plugins/linux_amd64
COPY --from=terraform-bundler-build /root/.terraform.d/ $HOME/.terraform.d/
RUN cp /bin/terraform-provider-google $HOME/.terraform.d/plugin-cache/linux_amd64
RUN cp /bin/terraform-provider-google-beta $HOME/.terraform.d/plugin-cache/linux_amd64

COPY terraformrc $HOME/.terraformrc

COPY provider.tf $HOME/
COPY backend.tf $HOME/

# For Testing (This should be echoed or taken care of in the CI pipeline)
#COPY google.json $HOME/.google.json
WORKDIR $HOME
ENTRYPOINT ["/bin/bash"]

.terraformrc:

plugin_cache_dir   = "$HOME/.terraform.d/plugins/linux_amd64"
disable_checkpoint = true

provider.tf

# Define which provider plugins are to be included
provider "google" {
  credentials = ".google.json"
}

provider "google-beta" {
  credentials = ".google.json"
}

my-build.sh

#!/usr/bin/env bash
#
# This script builds the application from source for multiple platforms.

# Get the parent directory of where this script is.
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )"

# Change into that directory
cd "$DIR"
echo "DIR=$DIR"

# Get the git commit
GIT_COMMIT=$(git rev-parse HEAD)
GIT_DIRTY=$(test -n "`git status --porcelain`" && echo "+CHANGES" || true)

# Determine the arch/os combos we're building for
XC_ARCH=${XC_ARCH:-"amd64 arm"}
XC_OS=${XC_OS:-linux}
XC_EXCLUDE_OSARCH="!darwin/arm !darwin/386"

mkdir -p bin/

# If its dev mode, only build for ourself
if [[ -n "${TF_DEV}" ]]; then
    XC_OS=$(go env GOOS)
    XC_ARCH=$(go env GOARCH)

    # Allow LD_FLAGS to be appended during development compilations
    LD_FLAGS="-X main.GitCommit=${GIT_COMMIT}${GIT_DIRTY} $LD_FLAGS"
fi

if ! which gox > /dev/null; then
    echo "==> Installing gox..."
    go get -u github.com/mitchellh/gox
fi

# Instruct gox to build statically linked binaries
export CGO_ENABLED=0

# In release mode we don't want debug information in the binary
if [[ -n "${TF_RELEASE}" ]]; then
    LD_FLAGS="-s -w"
fi

# Ensure all remote modules are downloaded and cached before build so that
# the concurrent builds launched by gox won't race to redundantly download them.
go mod download

# Build!
echo "==> Building..."
gox \
    -os="${XC_OS}" \
    -arch="${XC_ARCH}" \
    -osarch="${XC_EXCLUDE_OSARCH}" \
    -ldflags "${LD_FLAGS}" \
    -output "pkg/{{.OS}}_{{.Arch}}/${PWD##*/}" \
    .


## Move all the compiled things to the $GOPATH/bin
GOPATH=${GOPATH:-$(go env GOPATH)}
case $(uname) in
    CYGWIN*)
        GOPATH="$(cygpath $GOPATH)"
        ;;
esac
OLDIFS=$IFS
IFS=: MAIN_GOPATH=($GOPATH)
IFS=$OLDIFS
#
# Create GOPATH/bin if it's doesn't exists
if [ ! -d $MAIN_GOPATH/bin ]; then
    echo "==> Creating GOPATH/bin directory..."
    mkdir -p $MAIN_GOPATH/bin
fi

# Copy our OS/Arch to the bin/ directory
DEV_PLATFORM="./pkg/$(go env GOOS)_$(go env GOARCH)"
if [[ -d "${DEV_PLATFORM}" ]]; then
    for F in $(find ${DEV_PLATFORM} -mindepth 1 -maxdepth 1 -type f); do
        cp ${F} bin/
        cp ${F} ${MAIN_GOPATH}/bin/
        ls -alrt ${MAIN_GOPATH}/bin/
        echo "MAIN_GOPATH=${MAIN_GOPATH}"
    done
fi

bucket.tf

terraform {
  backend "gcs" {
    bucket = "my-terraform-bucket"
    prefix = "terraform/state"
    credentials = ".google.json"
  }
  required_version = "v0.12.20"
}

Обновлено Dockerfile для решения @ydaetskcoR, потому что в настоящее время terraform-bundle не работает с 0.12.x (проблема исправлена ​​в 0.12.2, но появилась 0.12.18)

FROM hashicorp/terraform:0.12.18 as terraform-provider

COPY provider.tf .

RUN terraform init && \
    mv .terraform/plugins/linux_amd64/terraform-provider* /bin/ 

FROM hashicorp/terraform:0.12.18
# Install terraform pre-installed plugins
COPY --from=terraform-provider /bin/terraform-provider* /bin/

А вот содержание provider.tf

provider "template" { version = "~>2.1.2" }
provider "aws" { version = "~>2.15.0" }
...
Другие вопросы по тегам