Home > Enterprise >  Terraform relation between docker-image and docker-container resource
Terraform relation between docker-image and docker-container resource

Time:08-29

I'm confused about the image property in the docker_container resource of a terraform tf file.

The following contents you see in all the tutorials:

resource "docker_image" "nginx" {
  name         = "nginx:latest"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.latest
  name  = "tutorial"
  ports {
    internal = 80
    external = 8000
  }
}

This pulls the latest image.

But if you want a previous image, you need to specify the Digest, like this:

resource "docker_image" "nginx" {
  name         = "nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f"
  keep_locally = false
}

Then you need to create a container on that image with the docker_container Resource. But there is no way you can specify that previous image tag or digest.

Things like image = docker_image.nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f all fail. Various syntax versions are tried (quotes, no-quotes, etc, etc). They all result in an error.

The only way I could get this working was with the following:

resource "docker_image" "nginx" {
  name         = "nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.latest
  name  = "Terraform-Nginx"
  ports {
    internal = 80
    external = 8000
  }
}

But now I'm confused.

What does ".latest" even mean in the image property of the docker_container resource?

CodePudding user response:

There are a couple of things to understand here. The first being the resource arguments and the second being the resource attributes [1]. In most of the providers, when you want to create a certain resource, you have to provide values for at least the required arguments. There are optional arguments as well. When a resource is successfully created, it provides a set of attributes which can be referenced in another resource. In your example, you cannot create a Docker container without specifying the image name. So instead of hardcoding the image name in the container resource, you first define the image resource and then reference its arguments/attributes in the container resource. The example you mention:

image = docker_image.nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f

is not valid because the Docker image resource provides no arguments and attributes named nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f, i.e., the provider schema knows nothing about that. The provider documentation has sections on arguments and attributes. The Docker provider documentation is lacking some of the usual elements, but in this case, the attributes seem to be denoted with Read-only section [2]. There you will find the latest attribute that you use for referencing an image that was pulled. Also note that it says that the argument is deprecated:

latest (String, Deprecated) The ID of the image in the form of sha256:<hash> image digest. Do not confuse it with the default latest tag.

Based on the current documentation, you might want to use the following:

resource "docker_container" "nginx" {
  image = docker_image.nginx.name
  name  = "tutorial"
  ports {
    internal = 80
    external = 8000
  }
}

The syntax used when referencing attributes/arguments is always:

<RESOURCE TYPE>.<NAME>.<ATTRIBUTE>

i.e., docker_image.nginx.latest or docker_iamge.nginx.name.

As a side note, to clear up any confusion, the way you are referencing the value for the image ID is called an implicit reference [3]. Since terraform creates resources in parallel, it helps when deciding the order in which the resources will be created. In this case the image will be pulled first and then the container will be created based on the image.

EDIT: updated the answer based on the input of @BertC.


[1] https://www.terraform.io/language/expressions/references#references-to-resource-attributes

[2] https://registry.terraform.io/providers/kreuzwerker/docker/latest/docs/resources/image#read-only

[3] https://www.terraform.io/language/resources/behavior#resource-dependencies

CodePudding user response:

In reaction to @MarkoE's answer :

Your answer showed to use the id string:

resource "docker_image" "nginx" {
  name         = "nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.id
  name  = "Terraform-Nginx"
  ports {
    internal = 80
    external = 8000
  }
}

This gave me the following error:

docker_container.nginx: Creating...
╷
│ Error: Unable to create container with image sha256:1b84ed9be2d449f4242c521a3961fb417ecf773d2456477691f109aab3c5bb74nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f: findImage1: error looking up local image 
"sha256:1b84ed9be2d449f4242c521a3961fb417ecf773d2456477691f109aab3c5bb74nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f": unable to inspect image 
sha256:1b84ed9be2d449f4242c521a3961fb417ecf773d2456477691f109aab3c5bb74nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f: Error response from daemon: no such image: 
sha256:1b84ed9be2d449f4242c521a3961fb417ecf773d2456477691f109aab3c5bb74nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f: invalid reference format

But from this link you provided I read:

The most common reference type is a reference to an attribute of a resource which has been declared either with a resource or data block.

Which made me change the code to:

resource "docker_image" "nginx" {
  name         = "nginx:1.22.0@sha256:f2dfca5620b64b8e5986c1f3e145735ce6e291a7dc3cf133e0a460dca31aaf1f"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.name
  name  = "Terraform-Nginx"
  ports {
    internal = 80
    external = 8000
  }
}

(Note the docker_image.nginx.name)

And now it works. I even get the right tag in the docker images command.

Tnanks Marko

  • Related