Source-to-Image (S2I) is a toolkit and workflow for building reproducible container images from source code. S2I produces ready-to-run images by inserting source code into a container image and letting the container prepare the source code. By creating self-assembling builder images, you can version and control your build environments exactly like you use container images to version your runtime environments.
For a dynamic language such as Ruby, the build time and run time environments are typically the same. Assuming that Ruby, Bundler, Rake, Apache, GCC, and all other packages needed to set up and run a Ruby application are already installed, a builder image performs the following steps:
The builder image starts a container with the application source injected into a known directory.
The container process transforms that source code into the appropriate runnable setup. For example, it installs dependencies with Bundler and moves the source code into a directory where Apache has been preconfigured to look for the Ruby configuration file.
It then commits the new container and sets the image entrypoint to be a script that will start Apache to host the Ruby application.
For compiled languages such as C, C++, Go, or Java, the necessary dependencies for compilation might outweigh the size of the runtime artifacts. To keep runtime images small, S2I enables a multiple-step build process, where a binary artifact such as an executable file is created in the first builder image, extracted, and injected into a second runtime image that simply places the executable program in the correct location.
For example, to create a reproducible build pipeline for Tomcat and Maven:
Create a builder image containing OpenJDK and Tomcat that expects to have a WAR file injected.
Create a second image that layers on top of the first image Maven and any other standard dependencies, and expects to have a Maven project injected.
Start S2I using the Java application source and the Maven image to create the desired application WAR.
Start S2I a second time using the WAR file from the earlier step and the initial Tomcat image to create the runtime image.
By placing build logic inside of images and combining the images into multiple steps, the runtime environment is close to the build environment without requiring the deployment of build tools to production.
Allow build environments to be tightly versioned by encapsulating them within a container image and defining a simple interface of injected source code for callers. Reproducible builds are a key requirement for enabling security updates and continuous integration in containerized infrastructure, and builder images help ensure repeatability and the ability to swap run times.
Any existing build system that can run on Linux can run inside of a container, and each individual builder can also be part of a larger pipeline. The scripts that process the application source code can be injected into the builder image, allowing authors to adapt existing images to enable source handling.
Instead of building multiple layers in a single Dockerfile, S2I encourages authors to represent an application in a single image layer. This saves time during creation and deployment and allows for better control over the output of the final image.
Dockerfiles are run without many of the normal operational controls of containers. They usually run as root and have access to the container network. S2I can control what permissions and privileges are available to the builder image since the build is launched in a single container. In concert with platforms like OpenShift, S2I allows administrators to control what privileges developers have at build time.
An OpenShift route exposes a service at a hostname so that external clients can reach it by name. When a Route
object is created on OpenShift, it gets picked up by the built-in HAProxy load balancer to expose the requested service and make it externally available with the given configuration.
Similar to the Kubernetes Ingress
object, Red Hat created the concept of route to fill a need and then contributed the design principles behind it to the community, which heavily influenced the Ingress
design. A route does have some additional features as can be seen in the following chart:
Feature | Ingress on OpenShift | Route on OpenShift |
---|---|---|
Standard Kubernetes object |
X |
|
External access to services |
X |
X |
Persistent (sticky) sessions |
X |
X |
Load-balancing strategies (e.g. round robin) |
X |
X |
Rate-limit and throttling |
X |
X |
IP whitelisting |
X |
X |
TLS edge termination for improved security |
X |
X |
TLS re-encryption for improved security |
X |
|
TLS passhtrough for improved security |
X |
|
Multiple weighted backends (split traffic) |
X |
|
Generated pattern-based hostnames |
X |
|
Wildcard domains |
X |
DNS resolution for a hostname is handled separately from routing. Your administrator might have configured a cloud domain that will always correctly resolve to the router or modify your unrelated hostname DNS records independently to resolve to the router. |
An individual route can override some defaults by providing specific configurations in its annotations.
An image stream stores a mapping of tags to images, metadata overrides that are applied when images are tagged in a stream, and an optional reference to a Docker image repository on a registry.
Using an image stream makes it easier to change a tag for a container image. Otherwise, to manually change a tag, you must download the image, change it locally, then push it all back. Promoting applications by manually changing a tag and then updating the deployment object entails many steps.
With image streams, you upload a container image once and then you manage its virtual tags internally in OpenShift. In one project you might use the developer tag and only change a reference to it internally, while in production you might use a production tag and also manage it internally. You do not have to deal with the registry.
You can also use image streams in conjunction with deployment configs to set a trigger that will start a deployment as soon as a new image appears or a tag changes its reference.
A build is the process of transforming input parameters into a resulting object. Most often, the process is used to transform input parameters or source code into a runnable image. A BuildConfig
object is the definition of the entire build process.
OpenShift Container Platform leverages Kubernetes by creating Docker-formatted containers from build images and pushing them to a container image registry.
Build objects share common characteristics:
Inputs for a build
Requirements to complete a build process
Logging the build process
Publishing resources from successful builds
Publishing the final status of the build
Builds take advantage of resource restrictions, specifying limitations on resources such as CPU usage, memory usage, and build or pod execution time.