使用预安装的Terraform插件,而不是通过terraform init下载它们

时间:2018-06-20 09:08:07

标签: terraform

在使用Terraform terraform init时运行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的服务器下载内容?

6 个答案:

答案 0 :(得分:14)

您可以通过将插件与terraform二进制文件放在同一目录中或通过设置-plugin-dir flag来使用预安装的插件。

还可以使用terraform-bundle tool自动为您需要的每个提供程序创建一个捆绑包。

我在Docker容器的CI管道中运行Terraform,所以有一个看起来像这样的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/

请注意,完成的容器映像还会添加gitmake和AWS CLI,因为在使用此容器的CI作业中我也需要这些工具。

terraform-bundle.hcl如下所示(取自terraform-bundle README):

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"]
}

答案 1 :(得分:1)

.terraformrc

config plugin_cache_dir

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

答案 2 :(得分:1)

从Terraform版本的0.13.2版本开始,可以通过网络镜像协议从本地Web服务器/ http服务器下载插件。

有关更多详细信息,请选中this link

它期望$ HOME路径中有一个TERRAFORM_CONFIG文件,指向如下所示的插件的提供者路径。如果文件位于其他目录中,则可以使用provider_installation { network_mirror { url = "https://terraform-plugins.example.net/providers/" } } env var提供路径。

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"
    }
  }
}

然后,您可以在自定义tf中定义提供程序,如下所示。

providers.tf ::

.zip

但是,您必须上载index.json格式的插件文件以及<version>.json{ "versions": { "2.3.0": {} } } 文件,以便terraform查找要下载的插件的版本。

包含插件版本的示例index.json:

<version>.json

同样,2.3.0.json包含插件文件的哈希值。在这种情况下,它是{ "archives": { "linux_amd64": { "hashes": [ "h1:nFL6uiwsQFLiP8QCr35sPfWe9LpXI3/c7gP9tYnih+k=" ], "url": "terraform-provider-random_2.3.0_linux_amd64.zip" } } }

index.json

如何获取<version>.jsonterraform providers文件的详细信息?

通过在包含tf文件的目录上运行terraform init。注意,运行此命令的机器需要连接到公共Terraform注册表。 Terraform将下载这些文件的信息。如果您有不同的terraform配置文件,则可以自动执行这些步骤,否则,可以手动进行:)

plugin-dir上,terraform从Web服务器上方而不是从terraform注册表中下载插件。确保您不要terraform init参数与test_label.text = "this a second test" 一起使用,因为它将覆盖您所做的所有更改。

答案 3 :(得分:1)

您可以通过设置“plugins-dir”标志将插件二进制文件放在可用 Terraform 二进制文件的同一目录中来使用预安装的插件。

默认情况下,所有插件都下载在 .terraform 文件夹中。例如,空资源插件将在以下位置可用

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

在 Terraform 目录下新建一个类似“terraform-plugins”的文件夹,将上面例子中提到的包括 registry.terraform.io 文件夹在内的所有内容复制到创建的文件夹中。

现在使用 plugins-dir 标志运行 terraform init 命令

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

使用 plugin-dir 标志指定完整的目录路径

答案 4 :(得分:0)

已更新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" }
...

答案 5 :(得分:0)

我花了一段时间,遇到了同样的问题。我最终不得不从源代码下载并使用此弹出的图像。它很讨厌,但是它可以做我需要做的才能与Google提供程序一起工作。

{
  "matches": [
    {
      "cacheDuration": "300s",
      "platformType": "ANY_PLATFORM",
      "threat": {
        "digest": null,
        "hash": null,
        "url": "http://badurl.com/",
        "ETag": null
      },
      "threatEntryMetadata": null,
      "threatEntryType": "URL",
      "threatType": "SOCIAL_ENGINEERING",
      "ETag": null
    }
  ],
  "ETag": null
}

.terraformrc:

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"]

provider.tf

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

my-build.sh

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

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

bucket.tf

#!/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