Are failing Jobs consuming resources on Kubernetes clusters?

lemmings off the cliff - Uh oh

Introduction

It is sometimes useful to assign tasks to containers, which will run them to completion. Unlike server processes these containers are expected to terminate. Typical use cases are:

  • Batch processing
  • Maintenance operation
  • Data processing

In OpenShift / Kubernetes a resource type Job exists for the purpose. Unlike a bare bone Pod, a Job is monitored by a controller that will continue to retry execution of the Pods until a specified number of them successfully terminate.

When the underlying mechanisms are not well understood the behavior of Jobs in failure scenarios and its impact on the cluster and its resources can be surprising. I got this simple question from one of the customers I work with: Are my failing jobs consuming resources on my OpenShift / Kubernetes cluster?
As often in IT the simple answer to a simple question is “it depends”. I realized that pieces of information to provide a more complete (and useful!) answer to the question are available but scattered in multiple places. This post is a trial of bringing all pieces together.

Separation of concerns

What is commonly understood as a Job failure, which may be more the failure of a container or a pod managed by a Job in certain cases, can be handled at two levels.

  • The Kubelet: this is the process part of Kubernetes platform that manages the Pod life cycle. It runs on every node and is only responsible for the pods on the same node.
  • The Job controller: resources are managed in Kubernetes by controllers, the Job controller is a central process that manages all Jobs for the complete cluster.

Now that we have set the scene let’s take concrete failure scenarios and look at what happens at the Node and cluster level.

CrashloopBackOff

Our first failure scenario is when Pods get into CrashloobBackOff. This is not unusual as it can happen under multiple circumstances.

  • The process inside the container terminates, possibly crashing with a non zero (success) exit code.
  • Fields of the Pod definition have been configured incorrectly, the image reference being a frequent culprit
  • Faulty configuration in Kubernetes. The list may be long as it can be anything from unreachable registry or API to issues with mounting volumes

Let’s create a simple Job referencing an image that does not exist and see what happens.

apiVersion: batch/v1
kind: Job
metadata:
  name: test
spec:
  selector: {}
  template:
    metadata:
      name: test
    spec:
      containers:
        - name: test
          resources:
            requests:
              cpu: 100m
              memory: 200Mi
          image: xxxx
          command:
            - /bin/bash
          args: 
            - "-c"
            - "sleep 30; exit 0;"
      restartPolicy: Never

Let’s check the status

  • At the Pod level we see that the events are pilling up: Pulling image “xxxx” followed by Error: ImagePullBackOff.
  • At the Job level everything seems normal: there is 1 active Pod and no failure event reported.

What is happening is the following:

  • The Job controller requested a Pod to be created to align the cluster status to what was requested by the Job creation
  • The Scheduler assigned the Pod to a Node
  • The Kubelet on the Node tried to create the containers for the Pod and failed to pull the image
  • The Kubelet continues to retry creating the containers

One may think that “restartPolicy: Never” may avoid this scenario but this is not the case. It would only apply if the container process was failing (non zero exit code). We will look at that later.

What does it mean for resources? At the node level failed containers are restarted by the Kubelet with an exponential back-off delay (10s, 20s, 40s…) capped at 5 minutes. This means in this scenario that CPU, memory and storage consumption is close to null as the container cannot be created.

At the cluster level it looks a bit different. When the Scheduler allocated the Pod to the Node, the requested resources (cpu: 100m and memory: 200Mi) have been reserved for the Pod. In a scenario with automated creation you may have thousands of such Pods reserving resources so that at some point all clusters resources may have been exhausted. New Pods requesting resources cannot be scheduled anymore.
A mechanism for protecting the cluster against that is to define a quota at the namespace level. When the quota has been reached Pods inside the namespace requesting resources are not admitted anymore but Pods in other namespaces can still be created.

Application failure

Let’s now make a very small change to our scenario. We will be referencing a valid image but the container will exit with a failure code.

apiVersion: batch/v1
kind: Job
metadata:
  name: test
spec:
  selector: {}
  template:
    metadata:
      name: test
    spec:
      containers:
        - name: test
          resources:
            requests:
              cpu: 100m
              memory: 200Mi
          image: image-registry.openshift-image-registry.svc:5000/openshift/httpd:latest
          command:
            - /bin/bash
          args: 
            - "-c"
            - "sleep 30; exit 1;"
      restartPolicy: Never

Let’s check the status again

  • At the Pod level we see that the status is now Failed and a new Pod gets created after the failure of the previous one.
  • At the Job level the failed Pods are now reported and after some time the Job is marked as Failed.

One thing that may be confusing is that we specified restartPolicy: Never. It is important to understand that the Job specification restart policy only applies to the Pods, and not the Job controller. If we had specified restartPolicy: OnFailure we will have the same behavior as in the preceding scenario. The Kubelet would restart the container and the Controller would not see the failure, the only difference being that the count of restarts is incremented at the Pod level (not at the Job level).

With Never as restartPolicy the Pod is failing and reported as such by the Kubelet. The Job controller reacts then by starting a new Pod. This new Pod may or may not be scheduled on the same Node. The number of times a new Pod is started is controlled by two parameters backoffLimit (default value is 6) and activeDeadlineSeconds (illimited by default). In our example we had not specified these parameters and the Pod got restarted 6 times. We can see 7 failed Pods at the end.

In terms of resources there is the regular consumption when a Pod is running. When Pods are terminated they don’t actively consume CPU or RAM resources but still use storage space on the Nodes for the logs. The resources for the Pod are not continuously reserved either. Only when the new Pod is scheduled. After the Pod has terminated the resource is released…. till a new Pod gets started. This however goes into the Scheduler work queue. If no Node with enough resource is available the Pod will need to wait.

Here it is important to have a limitation, hence the default value for backoffLimit. Without the limit you can quickly come to thousand of Pods that consume

  • storage space on the nodes for the logs
  • etcd space for the object definition
  • storage space in central logging
  • memory and storage space in Prometheus for metrics. Pod names are an unbounded set

Let’s consider impact of automation CronJobs or Jobs created by Continuous Integration (CI) tools with this scenario. I have seen clusters where there were more than hundred thousands of Jobs.

  • there were Out Of Memory (OOM) events for Prometheus
  • new Jobs were slow to start (taking 10 to 20 minutes)
  • API was slower than usual

An interesting point is that the cluster was still operational. It was possible to create Pods but creating the same Pods as part of a Job was taking a long time (not failing). It was really the creation of the Pod by the Job controller not the allocation (scheduling) of the Pod to a Node by the scheduler that was slow. The reason was the huge work queue of the Job controller. Nevertheless the Job controller may throttle new Pod creation due to excessive previous Pod failures in the same Job so that Pods for other Jobs get a chance to get created.

Note that Jobs don’t get automatically deleted after completion. It is a general good practice to remove them when they are not needed anymore as they increase the number of objects the API and etcd have to deal with. In case of CronJobs this can (and should) be done by configuring successfulJobsHistoryLimit and failedJobsHistoryLimit.

Conclusion

To conclude I will shortly mention two other scenarios.

When the service account specified in the Job does not exist the Job controller does not create a Pod and continuously retries it irrespective of the configured backofflimit.

When a PersistentVolumeClaim (PVC) is specified, which does not exist, the pod gets created but the scheduling fails. The pod stays in “Pending” state till its deletion or the creation of the PVC.

I hope this blog post provided a good overview of the components involved during Job failures, the caveats, protection mechanisms and, as the title reads, of the impact of Job failures on the cluster resources and their availability.

Thanks for reading!

Automating tests and metrics gathering for Kubernetes and OpenShift (part 3)

This is the third of a series of three articles based on a session I held at Red Hat Tech Exchange EMEA 2018. They were first published on developers.redhat.com. In the first article, I presented the rationale and approach for leveraging Red Hat OpenShift or Kubernetes for automated performance testing, and I gave an overview of the setup. In the second article, we looked at building an observability stack. In this third part, we will see how the execution of the performance tests can be automated and related metrics gathered.

An example of what is described in this article is available in my GitHub repository.

Continue reading

Building an observability stack for automated performance tests on Kubernetes and OpenShift (part 2)

This is the second of a series of three articles based on a session I held at Red Hat Tech Exchange 2018 in EMEA. They were first published on developers.redhat.com. In the first article, I presented the rationale and approach for leveraging Red Hat OpenShift or Kubernetes for automated performance testing, and I gave an overview of the setup.

In this article, we will look at building an observability stack. In production, the observability stack can help verify that the system is working correctly and performing well. It can also be leveraged during performance tests to provide insight into how the application performs under load.

An example of what is described in this article is available in my GitHub repository.

Continue reading

Structured application logs in OpenShift

Logs are like gold dust. Taken alone they may not be worth much, but put together and worked by a skillful goldsmith they may become very valuable. OpenShift comes with The EFK stack: Elasticsearch, Fluentd, and Kibana. Applications running on OpenShift get their logs automatically aggregated to provide valuable information on their state and health during tests and in production.

The only requirement is that the application sends its logs to the standard output. OpenShift does the rest. Simple enough!

In this blog I am covering a few points that may help you with bringing your logs from raw material to a more valuable product.

Continue reading

Container Images for OpenShift – Part 3: Making your images consumable

This is a transcript of a session I gave at EMEA Red Hat Tech Exchange 2017, a gathering of all Red Hat solution architects and consultants across EMEA. It is about considerations and good practices when creating images that will run on OpenShift. This third part focuses on how you can make your images easier to consume by application developers or release managers. Continue reading

Container Images for OpenShift – Part 2: Structuring your images

This is a transcript of a session I gave at EMEA Red Hat Tech Exchange 2017, a gathering of all Red Hat solution architects and consultants across EMEA. It is about considerations and good practices when creating images that will run on OpenShift. This second part focuses on how you should structure images and group of images to achieve the objectives stated in part one. Continue reading

Container Images for OpenShift – Part 1: Objectives

This is a transcript of a session I gave at EMEA Red Hat Tech Exchange 2017, a gathering of all Red Hat solution architects and consultants across EMEA. It is about considerations and good practices when creating images that will run on OpenShift. The content is structured in a series of four posts:

  • Objectives
  • Structuring your images
  • Making your images consumable
  • Cloud readiness

Continue reading

Development workflows with Fuse Integration Services (FIS)

This post was originally published on Red Hat Developers, the community to learn, code, and share faster. To read the original post, click here.

Development cycles

Fuse Integration Services (FIS) is a great product bringing routing (Apache Camel), SOAP and Rest services (CXF) and messaging (JMS) to the modern age of containers and PaaS and all its goodies: encapsulation, immutability, scalability and self healing. OpenShift provides the PaaS infrastructure to FIS.

In this blog entry I want to present the development workflows available with their pros and cons and I will stop there. A lot of information and great blogs have already been written that well describe approaches for CI and promotion. Here are a few pointers:

A developer may well implement a module in isolation on his own machine but it often makes sense, especially when we talk about integration services, to have the code being validated in a complex integrated environment. Something that OpenShift is great at providing. It is so easy to spawn an environment including frontend, backend and peer services that you may not want to wait for the integration test phase to see how your code performs and to identify where issues may happen. You want to see it right away, during your dev! This blog entry details a couple of workflows with their pros and cons for just doing that.

Project start

FIS provides several maven archetypes so that generating a complete working project, including a selection of modules (CXF, Camel for instance) and an already configured maven pom for generating a Docker image and pushing it into a registry is as simple as selecting a few items in dropdown lists of your favorite IDE or running a single command:

# mvn archetype:generate \
    -DarchetypeCatalog=https://repo.fusesource.com/nexus/content/groups/public/archetype-catalog.xml \
    -DarchetypeGroupId=io.fabric8.archetypes \
    -DarchetypeVersion=2.2.0.redhat-079 \
    -DarchetypeArtifactId=java-camel-spring-archetype

When that’s done you already have a project able to build your source code, to create a Docker container and to run it on OpenShift! You can focus on your code.

Fabric8 maven workflow

Let start with the default workflow in FIS. It consists in having maven building the Java artefacts and the Docker image locally and then pushing the generated image into the OpenShift registry. This works great and it is as easy as using the “mvn -Pf8-deploy” and the “mvn fabric8:json faric8:apply” commands.

This is well explained in the documentation [1].

The advantage of this worflow is that the developer can use the same configuration to build and run the application in a pre-Docker world and to have it deployed on OpenShift. That said it has a couple of requirements that may not make it suitable for every developer:

  • The developer will need to have Docker available where the build happens (on his machine or on a server, root access is currently required for Docker)
  • The developer will need to have the rights to push into the OpenShift registry (or to an external registry)

These are things that may be restricted in some companies. In the future the maven forkflow may support something called binary build to work around these limitations. We will see what it is and how you can use it today in the following chapters.

Source to Image (S2I) worflow

S2I is a framework provided by OpenShift that makes it easy to create Docker images from source code. The build happens directly in OpenShift so that you don’t need to have Docker available locally and to remotely push to the registry.

Per default the S2I process extracts the code from your source repository, spawns a container that builds your source code, generates a Docker image for your application and push it into the OpenShift registry. This is a great process, perfect for continuous integration, where you want to have a reproducible way of creating your application images.
Now looking at it from a developer point of view you may want to save a couple of steps in your development workflow and not want to commit into a git repository every change you are trying out. That’s where binary build can help you. We will look at it in the next chapter. Here is first an overview of the S2I workflow and where the time may get spent between the point where you trigger it and the point where your application is running in OpenShift. At first it may be quite disappointing as it takes a long long time but we will look at how this can be addressed.

overview
  1. The code is pulled from a git repository or from the developer machine after having been compressed and copied onto the S2I builder image
  2. The S2I builder image is pulled from the registry into the node, where the build will take place
  3. The maven build takes place, pulling the required dependencies and generating the application artefacts.
  4. A new Docker image is created, based on the FIS S2I image and containing the application artefacts.
  5. The Docker image is pushed into the OpenShift registry
  6. The container gets started on an OpenShift node

On my laptop running everything including OpenShift I get the following figures for the Camel Spring quickstart. You may have different values with dedicated servers but the order should still be similar.

  1. Copying the source code: between 1 and 16 seconds. I will explain the two values later on.
  2. Pulling the S2I image: 15 seconds
  3. Maven build: 25 minutes!
  4. Docker build: 16 seconds
  5. Docker push: 35 seconds
  6. Container start 7 seconds

Binary build

So we want to use binary build to avoid pushing our change into a git repository. Binary build consists in streaming your source code directly from your computer to the builder container. Nothing complicated and you can use the same build configuration that you use for your CI build.

Let assume that you have already created your application using the template: quickstart-template.json, provided by the maven archetype. You could have done that with the following command:

# oc new-app -f quickstart-template.json -p GIT_REPO=https://github.com/yourrepo/osev3-example.git

You will need to point the URL of the git repo to your own repository.

Triggering a binary build is then just a single command:

# oc start-build BUILDCONFIG --follow --from-repo=.

BUILDCONFIG needs to be replaced by the name of your build configuration.

An interesting point is that you don’t need to modify your build configuration for that. The command overwrite the source type “Git” to “Binary” behind the hood, which means that you can still use the same build configuration as in your CI process. In one case the sources are transferred from your local file system in the other case from your git server. Neat!

There are three flavour of binary builds:

  • –from-dir: the files in the specified directory are streamed to the builder image. It is to note that binaries in target directory may increase time to copy the sources if the application has first been built locally
  • –from-repo: the files in the local git repository are streamed to the builder image. It requires a git commit (not a push). The target directory is usually excluded through .gitignore.
  • –from-file: a zip archive is streamed to the builder image

You can display the build logs with the following command:

# oc logs bc/BUILDCONFIG

In the logs you can see for instance:

I0906 10:43:10.557946       1 sti.go:581] [INFO] ------------------------------------------------------------------------
I0906 10:43:10.557968       1 sti.go:581] [INFO] BUILD SUCCESS
I0906 10:43:10.557972       1 sti.go:581] [INFO] ------------------------------------------------------------------------
I0906 10:43:10.557975       1 sti.go:581] [INFO] Total time: 25:56 min

And that’s preceded by a long list of dependencies that get downloaded.

Using a maven mirror

Well, a usual way of addressing this kind of issue in the old world is to use a maven mirror, like Nexus or Artifactory, to cache the dependencies. It is not too different with OpenShift but dependency caching is critical here as the builder container does not have a pre-populated local .m2 repository (this may change in the future) and is like a new born baby every time a new build happen. You can set an environment variable so that your build uses a mirror. Therefore the build configuration can be edited and the maven mirror added under the source strategy:

"sourceStrategy": {
           "from": {
             "kind": "ImageStreamTag",
             "namespace": "openshift",
             "name": "fis-java-openshift:1.0"
           },
           "forcePull": true,
           "env": [
             {
               "name": "BUILD_LOGLEVEL",
               "value": "5"
             },
             {
               "name": "MAVEN_MIRROR_URL",
               "value": "nexus.ci-infra:8081/content/groups/public/"
             }

If your company does not already have a maven mirror available there is a Docker image with Nexus, which makes it possible to deploy a maven mirror in OpenShift in minutes. See this page for the details:

https://github.com/openshift/openshift-docs/blob/master/dev_guide/app_tutorials/maven_tutorial.adoc

Incremental builds

Another option to limit the amount of time required to download dependencies is using incremental builds. With incremental builds the dependencies contained in the .m2 directory get persisted at the end of the build and copied again to the builder image by the next build. You then have them locally.

A drawback of this approach compared to a maven mirror is that the artefacts are not shared between different applications, which means that your first build will still take very, very long.

To turn on incremental build, which will be activated per default with the next FIS release [2], you just need to amend the source strategy in the build configuration accordingly:

"sourceStrategy": {
           "from": {
             "kind": "ImageStreamTag",
             "namespace": "openshift",
             "name": "fis-java-openshift:1.0"
           },
           "forcePull": true,
           "env": [
             {
               "name": "BUILD_LOGLEVEL",
               "value": "5"
             }
           ],
           "incremental": true

Further considerations

Using a maven mirror or incremental builds we have now reduced the build time to a couple of minutes. That is totally acceptable as part of a CI process… but still not that good for a developer wanting to quickly test changes.

A few other considerations allow to further reduce the build time. The first one is nothing new. You may want to review your pom file and make sure that you need all the listed dependencies and plugins. Depending on your worflow you may for instance not need the Jolokia/docker plugin. Even if these plugins are not called during the artefact generation they have to be downloaded or copied into the builder image.

Another point to consider is that you don’t want your local target directory (and possibly others) getting streamed to the builder image. It may well be over 60 MB. If you use the –from-repo option make sure that you have .gitignore configured properly. Your git server will also thank you for that. If you use –from-dir make sure that your target directory has been cleansed before.

One step that costs around 15 seconds is that the Docker daemon running your build first downloads the latest S2I image before starting the build. You can save a bit of time by deactivating this mechanism called “force pull” in the build configuration:

"sourceStrategy": {
           "from": {
             "kind": "ImageStreamTag",
             "namespace": "openshift",
             "name": "fis-java-openshift:1.0"
           },
           "forcePull": false,

I would however strongly recommend to have the force pull option activated as part of your integration build, which will generate your reference image. If you deactivate it in the build configuration that you use during development you will have to support two different versions of the build configuration.

Hot deployment

Independent on whether you use the maven plugin or the S2I workflow you now have a process for building and deploying a change taking a few minutes. This is similar to what you may have had in the past when developing locally and not using a PaaS. A usual solution was then to hot deploy to shorten the time to something acceptable, probably under 30 seconds. How can you achieve this with FIS running on OpenShift?

Container technologies follow the principle that an image should be immutable. It should be possible to promote an image from one environment to the next, from QA to production for instance, and be sure to have the same behaviour in both environments. Image immutability provides consistency and reproducibility. This speaks against hot deployment and that surely one reason why it has been deactivated in the Karaf base image and it is not available with Hawtapp.

This sounds reasonable to you but does not help with having short cycles for applying changes?

We have two FIS flavors, one based on the OSGi container Karaf, the other one plain java. Let look at them one after the other.

Hot deployment with Apache Karaf

Hot deployment in Karaf is simply done by dropping a file in the deploy directory. Karaf will detect it and deploy it. As mentioned earlier this mechanism is deactivated in the Karaf assemble generated by the default pom. This can easily be activated by adding a couple of lines under the configuration of the karaf-maven-plugin:

<!-- deployer and aries-blueprint are required for hot deployment during the dev phase -->
<feature>deployer</feature>
<feature>aries-blueprint</feature>
<!-- shell and ssh are required to log in with the client during the dev phase -->
<feature>shell</feature>
<feature>ssh</feature>

Remember you should not have hot deployment in your reference image (the one being promoted from integration to production passing by QA and staging). Therefore it is best to create a dev profile in your pom, which is only activated on the developer machine. Again for reproducibility purpose the reference image should be created by your CI tool not manually by a developer.

So, we have now a hot deployment capable image but it has no access to your local file system. How does it work?

OpenShift has a nice feature for that: “oc rsync”. It allows to copy file to or from a container. In our case:

# oc rsync ./deployment/ POD:/deployments/karaf/deploy

This will transfer the files from the local deployment directory to the container. You just need to replace POD with the real name of your pod. Have a look at “oc rsync –help” for further options.

Last point: You can simply use “oc rsh POD” to get a shell inside your container. Karaf configuration is under /deployments/karaf/etc so that you can quickly test changes. Remember once the container is restarted all changes are lost.

That’s great to try out but you can always revert to the baseline (your image) by restarting the container. To change the baseline… just use the maven plugin or the S2I worfllow.

Hot deployment with Hawtapp

Hawtapp does not support hot deployment. This means that you may need to look at hot swapping for a solution, which is outside of the scope of this blog entry. Note that OpenShift allows to open a tunnel between your local machine and the remote container thanks to the command: “oc port-forward”. Use the “–help” option for the details of the command.

So yes we are not quite there with Hawtapp but the engineering team is looking at using Spring Boot for FIS 2.0 [4] and this comes with nice hot deployment and troubleshooting capabilities !

In the meantime a hybrid workflow with quick changes being tested locally and broader development tests being done in OpenShift may be the solution.

Java Console

Another nice feature of OpenShift is that it integrates a Java console for all the containers exposing a port named “jolokia”, what both the Karaf and Hawtapp images do per default. This gives you access to a nice web console similar to what you have with standalone Fuse instances. From the console you can follow the messages going through the camel routes, trace them, debug your camel routes or even modify them. This is great for troubleshooting!

To open the Java console, follow the link “Open Java Console” in the details page of the pod in your OpenShift web console:

link2console

You can then display your route:

route1

 

And modify the source:

route2

I hope you enjoyed reading this blog entry and congratulations if you made it till this last sentence!

 

Deactivation of non-TLS routes in Openshift v3

Introduction

OpenShift v3 comes with HAProxy as router per default. The router is used to expose services delivered by applications running inside OpenShift to the external world. With the current version of OpenShift 3.1 two port HTTP and TLS/SNI are configured on the router.
I have recently provided consulting on OpenShift for a customer, who was willing to disable the HTTP port on the router. When a route is created it is possible to define whether it is secured (encrypted) and what to do with the non-encrypted port (block, redirect or keep). The customer was however willing to take the option away from the route designer and enforce the company policy (external communication has to be encrypted) at the router level.
There may be more than a way of doing that. I would like here just to show how the HAProxy can be customized to fulfil this request by enforcing the redirection of unsecured connections to the TLS port. This approach may be used for other HAProxy customizations.

Customization

The default or current configuration of the HAProxy can be saved in an haproxynew folder with the following command

# docker run –rm –interactive=true –tty –entrypoint=cat
registry.access.redhat.com/openshift3/ose-haproxy-router:v3.1.1.6 haproxy-
config.template > haproxynew/haproxy-config.template

 

In the HAProxy configuration there is a section dedicated to the processing of unsecured requests:

# check if we need to redirect/force using https.
acl secure_redirect base,map_beg(/var/lib/haproxy/conf/os_edge_http_redirect.map) -m
found
redirect scheme https if secure_redirect

 

This section can be replaced as follows:

# force redirect/force using https.
redirect scheme https

 

A Dockerfile needs to be created so that an image can be generated with the new configuration

FROM openshift/origin-haproxy-router
ADD haproxynew/haproxy-config.template /var/lib/haproxy/conf/
ENV TEMPLATE_FILE=/var/lib/haproxy/conf/haproxy-config.template \RELOAD_SCRIPT=/var/lib/haproxy/reload-haproxy
ENTRYPOINT [“/usr/bin/openshift-router”]

 

The image can then get built locally

# docker build -t sandbox/haproxynew haproxynew

 

Finally the image can get tagged and pushed into the OpenShift registry or copied on the pods running the router. The new router can now get deployed.

# sudo oadm router router –replicas=1 –credentials=’/etc/origin/master/openshift
-router.kubeconfig’ –selector=’region=infra’ –service-account=router –default
-cert=apps-sandbox-com.pem –images=’sandbox/haproxynew’

 
We have now the following scenarios with the new router configuration:

  • The route has been created without tls: 503 service unavailable gets returned
  • The route has been created with http and tls: the insecureEdgeTerminationPolicy is ignored and the http connection gets always redirected to https.

That’s it!

Sandpit in OpenShift v3

Introduction

I have been doing an OpenShift v3 PoC for a customer and one member of the customer staff came up with an interesting use case for OpenShift, which is not what customers usually use it for. The idea is to be able to quickly spawn a container to evaluate or validate a package or configuration and to get it destroyed afterwards. The customer well understood that when the container terminates all modifications done are lost and he was fine with that. All what he wanted is really to have a sandpit, similar to what can be done with this docker command:

# sudo docker run -i -t rhel7 /bin/bash

The command just starts a RHEL image with a batch process.

The rational behind having it done in OpenShift rather than doing it directly with docker is that on one side sudo rights are needed to run docker on a server, which will only get granted to a limited number of employees. And on the other side the team in charge or managing computers may not be willing to provide support for docker on staff computer. OpenShift provides fine granularity for managing user rights and allows the execution of privileged operations in a secured way.

The OpenShift way

A container can easily get started with a batch process in Openshift with a command similar to the following one.

# oc run –restart=Never –attach –stdin –tty –image rhel7 rhel7 /bin/sh

Where things get more complicated is when the user wants to install new packages. This is generally not possible for security reasons when the container gets started in OpenShift by a standard user. A way to work around that is to create a Dockerfile extending the base image with the required packages. The image build will be launched by the builder service account, which is able to run privileged containers for this purpose. Here is an example of such a Dockerfile.

FROM rhel7.2# RHEL 7.2 Image extension for my Sandpit
#MAINTAINER Your Name <yourname@yourcompany.com>RUN INSTALL_PKGS=”tar httpd” && \
yum install -y $INSTALL_PKGS && \
rpm -V $INSTALL_PKGS && \
yum clean all

CMD [“/bin/bash”]

Once the image has been built you can “oc run” it as shown earlier. That’s it!