Managing Images

Overview

An image stream comprises any number of container images identified by tags. It presents a single virtual view of related images, similar to a Docker image repository.

By watching an image stream, builds and deployments can receive notifications when new images are added or modified and react by performing a build or deployment, respectively.

There are many ways you can interact with images and set up image streams, depending on where the images' registries are located, any authentication requirements around those registries, and how you want your builds and deployments to behave. The following sections cover a range of these topics.

Tagging Images

Before working with FaktorZ image streams and their tags, it will help to first understand image tags in the context of Docker generally.

Container images can have names added to them that make it more intuitive to determine what they contain, called a tag. Using a tag to specify the version of what is contained in the image is a common use case. If you have an image named ruby, you could have a tag named 2.0 for 2.0 version of Ruby, and another named latest to indicate literally the latest built image in that repository overall.

When interacting directly with images using the docker CLI, the docker tag command can add tags, which essentially adds an alias to an image that can consist of several parts. Those parts can include:

<registry_server>/<user_name>/<image_name>:<tag>

The <user_name> part in the above could also refer to a project or namespace if the image is being stored in an FaktorZ environment with an internal registry.

FaktorZ provides the oc tag command, which is similar to the docker tag command, but operates on image streams instead of directly on images.

See Red Hat Enterprise Linux 7’s Getting Started with Containers documentation for more about tagging images directly using the docker CLI.

Adding Tags to Image Streams

Keeping in mind that an image stream in FaktorZ comprises zero or more container images identified by tags, you can add tags to an image stream using the oc tag command:

$ oc tag <source> <destination>

For example, to configure the ruby image streams static-2.0 tag to always refer to the current image for the ruby image streams 2.0 tag:

$ oc tag ruby:2.0 ruby:static-2.0

There are different types of tags available. The default behavior uses a permanent tag, which points to a specific image in time; even when the source changes, the new (destination) tag will not change.

A tracking tag means the destination tag’s metadata will be updated during the import of the source tag. To ensure the destination tag is updated whenever the source tag changes, use the --alias=true flag:

$ oc tag --alias=true <source> <destination>

Use a tracking tag for creating permanent aliases (for example, latest or stable). The tag works correctly only within a single image stream. Trying to create a cross-image-stream alias will produce an error.

You can also add the --scheduled=true flag to have the destination tag be refreshed (i.e., re-imported) periodically. The period is configured globally at system level. See Importing Tag and Image Metadata for more details.

The --reference flag will create an image stream tag that is not imported. The tag will simply point to the source location, permanently.

If you want to instruct Docker to always fetch the tagged image from the integrated registry, use --reference-policy=local. The registry uses the pull-through feature to serve the image to the client. By default, the image blobs are mirrored locally by the registry. As a result, they are available for a shorter time the next time they are needed. The flag also allows for pulling from insecure registries without a need to supply --insecure-registry to the Docker daemon as long as the image stream has an insecure annotation or the tag has an insecure import policy.

Tag Naming

Images evolve over time and the tag reflects this. It always points to the latest image built. If there is too much information embedded in a tag name (for example, v2.0.1-may-2016), the tag will point to just one revision of an image and will never be updated. Using default image pruning options, such an image will never be removed. Instead, if the tag is named v2.0, more image revisions are more likely. This results in longer tag history and, therefore, the image pruner will more likely remove old and unused images.

Although tag naming convention is up to you, here are a few examples:

Description Example

Revision

v2.0.1

Architecture

v2.0-x86_64

Base image

v1.2-centos7

If you require dates in tag names, periodically inspect old and unsupported images and istags and remove them. Otherwise, you might experience increasing resource usage caused by old images.

Removing Tags from Image Streams

To remove a tag completely from an image stream run:

$ oc delete istag/ruby:latest

or:

$ oc tag -d ruby:latest

Referencing Images in Image Streams

Images can be referenced in image streams using the following reference types:

  • An ImageStreamTag is used to reference or retrieve an image for a given image stream and tag. It uses the following convention for its name:

    <image_stream_name>:<tag>
  • An ImageStreamImage is used to reference or retrieve an image for a given image stream and image name. It uses the following convention for its name:

    <image_stream_name>@<id>

    The <id> is an immutable identifier for a specific image, also called a digest.

  • A DockerImage is used to reference or retrieve an image for a given external registry. It uses standard Docker pull specification for its name, e.g.:

    openshift/ruby-20-centos7:2.0

    When no tag is specified, it is assumed the latest tag will be used.

    You can also reference a third-party registry:

    registry.access.redhat.com/rhel7:latest

    Or an image with a digest:

    centos/ruby-22-centos7@sha256:3a335d7d8a452970c5b4054ad7118ff134b3a6b50a2bb6d0c07c746e8986b28e

When viewing example image stream definitions, such as the example CentOS image streams, you may notice they contain definitions of ImageStreamTag and references to DockerImage, but nothing related to ImageStreamImage.

This is because the ImageStreamImage objects are automatically created in FaktorZ whenever you import or tag an image into the image stream. You should never have to explicitly define an ImageStreamImage object in any image stream definition that you use to create image streams.

You can view an image’s object definition by retrieving an ImageStreamImage definition using the image stream name and ID:

$ oc export isimage <image_stream_name>@<id>

You can find valid <id> values for a given image stream by running:

$ oc describe is <image_stream_name>

For example, from the ruby image stream asking for the ImageStreamImage with the name and ID of ruby@3a335d7:

Example 1. Definition of an Image Object Retrieved via ImageStreamImage
$ oc export isimage ruby@3a335d7

apiVersion: v1
image:
  dockerImageLayers:
  - name: sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    size: 0
  - name: sha256:ee1dd2cb6df21971f4af6de0f1d7782b81fb63156801cfde2bb47b4247c23c29
    size: 196634330
  - name: sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    size: 0
  - name: sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    size: 0
  - name: sha256:ca062656bff07f18bff46be00f40cfbb069687ec124ac0aa038fd676cfaea092
    size: 177723024
  - name: sha256:63d529c59c92843c395befd065de516ee9ed4995549f8218eac6ff088bfa6b6e
    size: 55679776
  dockerImageMetadata:
    Architecture: amd64
    Author: SoftwareCollections.org <sclorg@redhat.com>
    Config:
      Cmd:
      - /bin/sh
      - -c
      - $STI_SCRIPTS_PATH/usage
      Entrypoint:
      - container-entrypoint
      Env:
      - PATH=/opt/app-root/src/bin:/opt/app-root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
      - STI_SCRIPTS_URL=image:///usr/libexec/s2i
      - STI_SCRIPTS_PATH=/usr/libexec/s2i
      - HOME=/opt/app-root/src
      - BASH_ENV=/opt/app-root/etc/scl_enable
      - ENV=/opt/app-root/etc/scl_enable
      - PROMPT_COMMAND=. /opt/app-root/etc/scl_enable
      - RUBY_VERSION=2.2
      ExposedPorts:
        8080/tcp: {}
      Image: d9c3abc5456a9461954ff0de8ae25e0e016aad35700594714d42b687564b1f51
      Labels:
        build-date: 2015-12-23
        io.k8s.description: Platform for building and running Ruby 2.2 applications
        io.k8s.display-name: Ruby 2.2
        io.openshift.builder-base-version: 8d95148
        io.openshift.builder-version: 8847438ba06307f86ac877465eadc835201241df
        io.openshift.expose-services: 8080:http
        io.openshift.s2i.scripts-url: image:///usr/libexec/s2i
        io.openshift.tags: builder,ruby,ruby22
        io.s2i.scripts-url: image:///usr/libexec/s2i
        license: GPLv2
        name: CentOS Base Image
        vendor: CentOS
      User: "1001"
      WorkingDir: /opt/app-root/src
    ContainerConfig: {}
    Created: 2016-01-26T21:07:27Z
    DockerVersion: 1.8.2-el7
    Id: 57b08d979c86f4500dc8cad639c9518744c8dd39447c055a3517dc9c18d6fccd
    Parent: d9c3abc5456a9461954ff0de8ae25e0e016aad35700594714d42b687564b1f51
    Size: 430037130
    apiVersion: "1.0"
    kind: DockerImage
  dockerImageMetadataVersion: "1.0"
  dockerImageReference: centos/ruby-22-centos7@sha256:3a335d7d8a452970c5b4054ad7118ff134b3a6b50a2bb6d0c07c746e8986b28e
  metadata:
    creationTimestamp: 2016-01-29T13:17:45Z
    name: sha256:3a335d7d8a452970c5b4054ad7118ff134b3a6b50a2bb6d0c07c746e8986b28e
    resourceVersion: "352"
    uid: af2e7a0c-c68a-11e5-8a99-525400f25e34
kind: ImageStreamImage
metadata:
  creationTimestamp: null
  name: ruby@3a335d7
  namespace: openshift
  selflink: /oapi/v1/namespaces/openshift/imagestreamimages/ruby@3a335d7

Image Pull Policy

Each container in a pod has a container image. Once you have created an image and pushed it to a registry, you can then refer to it in the pod.

When FaktorZ creates containers, it uses the container’s imagePullPolicy to determine if the image should be pulled prior to starting the container. There are three possible values for imagePullPolicy:

  • Always - always pull the image.

  • IfNotPresent - only pull the image if it does not already exist on the node.

  • Never - never pull the image.

If a container’s imagePullPolicy parameter is not specified, FaktorZ sets it based on the image’s tag:

  1. If the tag is latest, FaktorZ defaults imagePullPolicy to Always.

  2. Otherwise, FaktorZ defaults imagePullPolicy to IfNotPresent.

Accessing the Internal Registry

You can access FaktorZ’s internal registry directly to push or pull images. For example, this could be helpful if you wanted to create an image stream by manually pushing an image, or just to docker pull an image directly.

FaktorZ Online gives developers a hands-on preview of the FaktorZ platform in a hosted environment that includes access to an internal registry.

The internal registry authenticates using the same tokens as the FaktorZ API. To perform a docker login against the internal registry, you can choose any user name and email, but the password must be a valid FaktorZ token.

To log into the internal registry:

  1. Log in to FaktorZ:

    $ oc login
  2. Get your access token:

    $ oc whoami -t
  3. Log in to the internal registry using the token. You must have docker installed on your system:

    $ docker login -u <user_name> -e <email_address> \
        -p <token_value> https://registry.<clusterID>.openshift.com

    Contact your cluster administrator if you do not know the registry IP or host name and port to use.

In order to pull an image, the authenticated user must have get rights on the requested imagestreams/layers. In order to push an image, the authenticated user must have update rights on the requested imagestreams/layers.

By default, all service accounts in a project have rights to pull any image in the same project, and the builder service account has rights to push any image in the same project.

Pulling from Private Registries with Delegated Authentication

A private registry can delegate authentication to a separate service. In these cases, image pull secrets must be defined for both the authentication and registry endpoints.

Third-party images in the Red Hat Container Catalog are served from the Red Hat Connect Partner Registry (registry.connect.redhat.com). This registry delegates authentication to sso.redhat.com, so the following procedure applies.

  1. Create a secret for the delegated authentication server:

    $ oc secret new-dockercfg \
        --docker-server=sso.redhat.com \
        --docker-username=developer@example.com \
        --docker-password=******** \
        --docker-email=unused \
        redhat-connect-sso
    
    secret/redhat-connect-sso
  2. Create a secret for the private registry:

    $ oc secret new-dockercfg \
        --docker-server=privateregistry.example.com \
        --docker-username=developer@example.com \
        --docker-password=******** \
        --docker-email=unused \
        private-registry
    
    secret/private-registry

The Red Hat Connect Partner Registry (registry.connect.redhat.com) does not accept the auto-generated dockercfg secret type (BZ#1476330). A generic file-based secret must be created using the generated file from a docker login command:

$ docker login registry.connect.redhat.com --username developer@example.com

Password: *************
Login Succeeded

$ oc secret new redhat-connect .dockerconfigjson=/root/.docker/config.json

$ oc secrets link default redhat-connect --for=pull

Importing Tag and Image Metadata

An image stream can be configured to import tag and image metadata from an image repository in an external Docker image registry. You can do this using a few different methods.

  • You can manually import tag and image information with the oc import-image command using the --from option:

    $ oc import-image <image_stream_name>[:<tag>] --from=<docker_image_repo> --confirm

    For example:

    $ oc import-image my-ruby --from=docker.io/openshift/ruby-20-centos7 --confirm
    The import completed successfully.
    
    Name:			my-ruby
    Created:		Less than a second ago
    Labels:			<none>
    Annotations:		openshift.io/image.dockerRepositoryCheck=2016-05-06T20:59:30Z
    Docker Pull Spec:	172.30.94.234:5000/demo-project/my-ruby
    
    Tag	Spec					Created			PullSpec							Image
    latest	docker.io/openshift/ruby-20-centos7	Less than a second ago	docker.io/openshift/ruby-20-centos7@sha256:772c5bf9b2d1e8...	<same>

    You can also add the --all flag to import all tags for the image instead of just latest.

  • Like most objects in FaktorZ, you can also write and save a JSON or YAML definition to a file then create the object using the CLI. Set the spec.dockerImageRepository field to the Docker pull spec for the image:

    apiVersion: "v1"
    kind: "ImageStream"
    metadata:
      name: "my-ruby"
    spec:
      dockerImageRepository: "docker.io/openshift/ruby-20-centos7"

    Then create the object:

    $ oc create -f <file>

When you create an image stream that references an image in an external Docker registry, FaktorZ communicates with the external registry within a short amount of time to get up to date information about the image.

After the tag and image metadata is synchronized, the image stream object would look similar to the following:

apiVersion: v1
kind: ImageStream
metadata:
  name: my-ruby
  namespace: demo-project
  selflink: /oapi/v1/namespaces/demo-project/imagestreams/my-ruby
  uid: 5b9bd745-13d2-11e6-9a86-0ada84b8265d
  resourceVersion: '4699413'
  generation: 2
  creationTimestamp: '2016-05-06T21:34:48Z'
  annotations:
    openshift.io/image.dockerRepositoryCheck: '2016-05-06T21:34:48Z'
spec:
  dockerImageRepository: docker.io/openshift/ruby-20-centos7
  tags:
    -
      name: latest
      annotations: null
      from:
        kind: DockerImage
        name: 'docker.io/openshift/ruby-20-centos7:latest'
      generation: 2
      importPolicy: {  }
status:
  dockerImageRepository: '172.30.94.234:5000/demo-project/my-ruby'
  tags:
    -
      tag: latest
      items:
        -
          created: '2016-05-06T21:34:48Z'
          dockerImageReference: 'docker.io/openshift/ruby-20-centos7@sha256:772c5bf9b2d1e8e80742ed75aab05820419dc4532fa6d7ad8a1efddda5493dc3'
          image: 'sha256:772c5bf9b2d1e8e80742ed75aab05820419dc4532fa6d7ad8a1efddda5493dc3'
          generation: 2

You can set a tag to query external registries at a scheduled interval to synchronize tag and image metadata by setting the --scheduled=true flag with the oc tag command as mentioned in Adding Tags to Image Streams.

Alternatively, you can set importPolicy.scheduled to true in the tag’s definition:

apiVersion: v1
kind: ImageStream
metadata:
  name: ruby
spec:
  tags:
  - from:
      kind: DockerImage
      name: openshift/ruby-20-centos7
    name: latest
    importPolicy:
      scheduled: true

Importing Images from Insecure Registries

An image stream can be configured to import tag and image metadata from insecure image registries, such as those signed with a self-signed certificate or using plain HTTP instead of HTTPS.

To configure this, add the openshift.io/image.insecureRepository annotation and set it to true. This setting bypasses certificate validation when connecting to the registry:

kind: ImageStream
apiVersion: v1
metadata:
  name: ruby
  annotations:
    openshift.io/image.insecureRepository: "true" (1)
  spec:
    dockerImageRepository: my.repo.com:5000/myimage
1 Set the openshift.io/image.insecureRepository annotation to true

This option instructs integrated registry to fall back to an insecure transport for any external image tagged in the image stream when serving it, which is dangerous. If possible, avoid this risk by marking just an istag as insecure.

Image Stream Tag Policies

Insecure Tag Import Policy

The above annotation applies to all images and tags of a particular ImageStream. For a finer-grained control, policies may be set on istags. Set importPolicy.insecure in the tag’s definition to true to allow a fall-back to insecure transport just for images under this tag.

The fall-back to insecure transport for an image under particular istag will be enabled either when the image stream is annotated as insecure or the istag has insecure import policy. The importPolicy.insecure` set to false can not override the image stream annotation.

Reference Policy

The Reference Policy allows you to specify from where resources that reference this image stream tag will pull the image. It is only applicable to remote images (those imported from external registries). There are two options to choose from, Local and Source.

The Source policy instructs clients to pull directly from the source registry of the image. The integrated registry is not involved unless the image is managed by the cluster. (It is not an external image.) This is the default policy.

The Local policy instructs clients to always pull from the integrated registry. This is useful if you want to pull from external insecure registries without modifying Docker daemon settings.

The pull-through feature of the registry serves the remote image to the client. Additionally, all the blobs are mirrored for faster access later.

You can set the policy in a specification of image stream tag as referencePolicy.type.

Example 2. Exmple of Insecure Tag with a Local Reference Policy
kind: ImageStream
apiVersion: v1
metadata:
  name: ruby
  tags:
  - from:
      kind: DockerImage
      name: my.repo.com:5000/myimage
    name: mytag
    importPolicy:
      insecure: true (1)
    referencePolicy:
      type: Local (2)
1 Set tag mytag to use an insecure connection to that registry.
2 Set tag mytag to use integrated registry for pulling external images. If the reference policy type is set to Source, clients fetch the image directly from my.repo.com:5000/myimage.

Creating an Image Stream by Manually Pushing an Image

An image stream can also be automatically created by manually pushing an image to the internal registry. This is only possible when using an FaktorZ internal registry.

Before performing this procedure, the following must be satisfied:

  • The destination project you push to must already exist.

  • The user must be authorized to {get, update} "imagestream/layers" in that project. In addition, since the image stream does not already exist, the user must be authorized to {create} "imagestream" in that project. If you are a project administrator, then you would have these permissions.

The system:image-pusher role does not grant permission to create new image streams, only to push images to existing image streams, so it cannot be used to push images to image streams that do not yet exist unless additional permissions are also granted to the user.

To create an image stream by manually pushing an image:

  1. First, log in to the internal registry.

  2. Then, tag your image using the appropriate internal registry location. For example, if you had already pulled the docker.io/centos:centos7 image locally:

    $ docker tag docker.io/centos:centos7 172.30.48.125:5000/test/my-image
  3. Finally, push the image to your internal registry. For example:

    $ docker push 172.30.48.125:5000/test/my-image
    The push refers to a repository [172.30.48.125:5000/test/my-image] (len: 1)
    c8a648134623: Pushed
    2bf4902415e3: Pushed
    latest: digest: sha256:be8bc4068b2f60cf274fc216e4caba6aa845fff5fa29139e6e7497bb57e48d67 size: 6273
  4. Verify that the image stream was created:

    $ oc get is
    NAME       DOCKER REPO                        TAGS      UPDATED
    my-image   172.30.48.125:5000/test/my-image   latest    3 seconds ago

Triggering Updates on Image Stream Changes

When an image stream tag is updated to point to a new image, FaktorZ can automatically take action to roll the new image out to resources that were using the old image. This is configured in different ways depending on the type of resource that is referencing the image stream tag.

FaktorZ Resources

FaktorZ DeploymentConfigs and BuildConfigs can be automatically triggered by changes to ImageStreamTags. The triggered action can be run using the new value of the image referenced by the updated ImageStreamTag. For more details on using this capability see the documentation on BuildConfig triggers and DeploymentConfig triggers.

Kubernetes Resources

Unlike DeploymentConfigs and BuildConfigs, which include as part of their API definition a set of fields for controlling triggers, Kubernetes resources do not have fields for triggering. Instead, FaktorZ uses annotations to allow users to request triggering. The annotation is defined as follows:

Key: image.openshift.io/triggers
Value: array of triggers, where each item has the schema:
[
 {
   "from" :{
     "kind": "ImageStreamTag", // required, the resource to trigger from, must be ImageStreamTag
     "name": "example:latest", // required, the name of an ImageStreamTag
     "namespace": "myapp",     // optional, defaults to the namespace of the object
   },
   // required, JSON path to change
   // Note that this field is limited today, and only accepts a very specific set
   // of inputs (a JSON path expression that precisely matches a container by ID or index).
   // For pods this would be "spec.containers[?(@.name='web')].image".
   "fieldPath": "spec.template.spec.containers[?(@.name='web')].image",
   // optional, set to true to temporarily disable this trigger.
   "paused": "false"
 },
 ...
]

When FaktorZ sees one of the core Kubernetes resources that contains both a pod template (i.e, only CronJobs, Deployments, StatefulSets, DaemonSets, Jobs, ReplicaSets, ReplicationControllers, and Pods) and this annotation, it will attempt to update the object using the image currently associated with the ImageStreamTag referenced by trigger. The update is performed against the fieldPath specified.

In the following example the trigger will fire when the example:latest imagestream tag is updated. Upon firing, the object’s pod template image reference for the web container will be updated with a new image value. If the pod template is part of a Deployment definition, the change to the pod template will automatically trigger a deployment, effectively rolling out the new image.

image.openshift.io/triggers=[{"from":{"kind":"ImageStreamTag","name":"example:latest"},"fieldPath":"spec.template.spec.containers[?(@.name='web')].image"}]

When adding an Image Trigger to Deployments, you can also use the oc set triggers command. For example the following command will add an image change trigger to the Deployment named example such that when the example:latest image stream tag is updated, the web container inside the deployment will be updated with the new image value:

$ oc set triggers deploy/example --from-image=example:latest -c web

Unless the Deployment is paused, this pod template update will automatically cause a deployment to occur with the new image value.

Writing Image Streams for S2I Builders

Image streams for S2I builders that are displayed in the management console’s catalog page require additional metadata to provide the best experience for end users.

Example 3. Definition of an Image Stream Object with Catalog Metadata
apiVersion: v1
kind: ImageStream
metadata:
  name: ruby
  annotations:
    openshift.io/display-name: Ruby (1)
spec:
  tags:
    - name: '2.0' (2)
      annotations:
        openshift.io/display-name: Ruby 2.0 (3)
        description: >- (4)
          Build and run Ruby 2.0 applications on CentOS 7. For more information
          about using this builder image, including FaktorZ considerations,
          see
          https://github.com/sclorg/s2i-ruby-container/tree/master/2.0/README.md.
        iconClass: icon-ruby (5)
        sampleRepo: 'https://github.com/openshift/ruby-ex.git' (6)
        tags: 'builder,ruby' (7)
        supports: 'ruby' (8)
        version: '2.0' (9)
      from:
        kind: DockerImage
        name: 'openshift/ruby-20-centos7:latest'
1 A brief, user-friendly name for the whole image stream.
2 The tag is referred to as the version. Tags appear in a drop-down menu.
3 A user-friendly name for this tag within the image stream. This should be brief and include version information when appropriate.
4 A description of the tag, which includes enough detail for users to understand what the image is providing. It can include links to additional instructions. Limit the description to a few sentences.
5 The icon to show for this tag. Pick from our existing logo icons when possible. Icons from FontAwesome and Patternfly can also be used. Alternatively, provide icons through CSS customizations that can be added to a FaktorZ cluster that uses your image stream. You must specify an icon class that exists, or it will prevent falling back to the generic icon.
6 A URL to a source repository that works with this builder image tag and results in a sample running application.
7 Categories that the image stream tag is associated with. The builder tag is required for it to show up in the catalog. Add tags that will associate it with one of the provided catalog categories. Refer to the id and categoryAliases in CATALOG_CATEGORIES in the console’s constants file. The categories can also be customized for the whole cluster.
8 Languages this image supports. This value will be used during oc new-app invocations to try to match potential builder images to the provided source repository.
9 Version information for this tag.