springwell
springwell

Reputation: 3151

How can I keep a container running on Kubernetes?

I'm now trying to run a simple container with shell (/bin/bash) on a Kubernetes cluster.

I thought that there was a way to keep a container running on a Docker container by using pseudo-tty and detach option (-td option on docker run command).

For example,

$ sudo docker run -td ubuntu:latest

Is there an option like this in Kubernetes?

I've tried running a container by using a kubectl run-container command like:

kubectl run-container test_container ubuntu:latest --replicas=1

But the container exits for a few seconds (just like launching with the docker run command without options I mentioned above). And ReplicationController launches it again repeatedly.

Is there a way to keep a container running on Kubernetes like the -td options in the docker run command?

Upvotes: 304

Views: 605142

Answers (18)

JohnInJax
JohnInJax

Reputation: 11

Keep a Kubernetes pod open (medium article)

Keep a pod running (YouTube)

Create a pod with stdin: true

This keeps the container process' stdin open waiting for a connection. As a result the pod stays open and you can shell in as needed.

Then kubectl exec -it ubuntu -- /bin/bash

Boom, you have a pod of whatever image you need running and staying open. Shell into it at will.

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: ubuntu
  name: ubuntu
spec:
  containers:
  - image: ubuntu:latest
    name: ubuntu
    stdin: true
  dnsPolicy: ClusterFirst
  restartPolicy: Always

Upvotes: 0

Vinoth D
Vinoth D

Reputation: 11

You can make a container running on kubernetes based on the DockerFile of the image used for container

We can look this in two scenarios

Scenario 1:

If we need to run nginx container it doesnt need any command to be passed as argument. This can be found from the last line (CMD) in Docker file of nginx

Docker file source: https://github.com/nginxinc/docker-nginx/blob/a6f7d140744f8b15ff4314b8718b3f022efc7f43/mainline/debian/Dockerfile

CMD ["nginx", "-g", "daemon off;"]

As per the above CMD, the image will start a process (ie) nginx once it is run and hence we dont need to pass any command's to make a container running

kubectl run nginx --image=nginx

Scenario 2 :

If we want to run busybox container the last line of Docker file says below

CMD ["sh"]

Docker file source: https://github.com/docker-library/busybox/blob/557fc6b60c652465f82bb915e7c55ab46984ceaf/latest-1/glibc/Dockerfile

As per the above CMD, the image will not start a process and will only run sh command (which is a shell command) which is not sufficient to make container up and running. Hence we need to pass commands which will run in the shell to make container alive is as below

kubectl run busybox --image=busybox --command -- top

In the above example I am running a top command which will make a container alive and running.

Upvotes: 1

Xai
Xai

Reputation: 1

edit deployment and add:

          command:
            - /bin/bash
            - sleep 1000 

to spec.template.spec.containers section

Upvotes: 0

Alter
Alter

Reputation: 1223

If you want to keep images pre-cached in the nodes, I think that could be the idea, you can have a daemonset that distribute the pod image to all nodes or those that you are interested, and you can use sleep infinity to keep the containers alive and also avoid that the images to be cleaned up by k8s GC. Note: Keep in mind the some docker images does not contains /bin/sh binary, for those you need a workaround. Sharing below the example where the /bin/sh binary is not present, if that is not your case, then just delete the initContainers and the volumes that shares the binary files to the containers. In the example busybox is used, you can also adjust the initContainers and use the one that contains the missing binary.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: image-cache
  namespace: default # adjust the namespace
spec:
  selector:
    matchLabels:
      app: image-cache
  template:
    metadata:
      labels:
        app: image-cache
    spec:
      # Specify node affinity if you need it
      # Specify security context global if you need it
      initContainers:
        - name: busybox-musl
          image: busybox:musl
          command:
            - sh
          args:
            - -c
            - |
              echo "Copying binary..."
              cp /bin/busybox /usr/shared/binaries
              chown 1000:1000 /usr/shared/binaries/busybox
              chmod 775 /usr/shared/binaries/busybox
              echo "... Done."
          volumeMounts:
            - name: busybox-shared
              mountPath: /usr/shared/binaries
      containers:
        - name: container-name
          image: desired-container-image:version
          command:
            - /usr/shared/binaries/busybox
          args:
            - sleep
            - infinity
          volumeMounts:
            - name: busybox-shared
              mountPath: "/usr/shared/binaries"
      volumes:
        - name: busybox-shared
          emptyDir: {}

Upvotes: 0

Joel Wembo
Joel Wembo

Reputation: 900

This command may help

CMD exec /bin/bash -c "trap : TERM INT; sleep i infinity & wait"

Upvotes: 0

Maha Hamza
Maha Hamza

Reputation: 89

add this : in template ->in spec-> in container ->in ports & after container port line

    command: ["/bin/sh", "-ec", "while :; do echo '.'; sleep 6 ; done"]

Upvotes: 9

Arbaaz
Arbaaz

Reputation: 981

In order to keep a POD running it should to be performing certain task, otherwise Kubernetes will find it unnecessary, therefore it stops. There are many ways to keep a POD running.

I have faced similar problems when I needed a POD just to run continuously without doing any useful operation. The following are the two ways those worked for me:

  1. Running sleep command while running the container.
  2. Running an infinite loop inside the container.

Although the first option is easier than the second one and may suffice the requirement, it is not the best option. As, there is a limit as far as the number of seconds you are going to assign in the sleep command. But a container with infinite loop running inside it never exits.

However, I will describe both the ways(Considering you are running busybox container):

1. Sleep Command

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  containers:
  - name: busybox
    image: busybox
    ports:
    - containerPort: 80
    command: ["/bin/sh", "-ec", "sleep 1000"]

2. Infinite Loop

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  containers:
  - name: busybox
    image: busybox
    ports:
    - containerPort: 80
    command: ["/bin/sh", "-ec", "while :; do echo '.'; sleep 5 ; done"]

Run the following command to run the pod:

kubectl apply -f <pod-yaml-file-name>.yaml

Hope it helps!

Upvotes: 69

Hackaholic
Hackaholic

Reputation: 19763

I did a hack by putting it in background:

[root@localhost ~]# kubectl run hello -it --image ubuntu -- bash &
[2] 128461

Exec on pod hello

[root@localhost ~]# kubectl exec -it hello -- whoami
root
[root@localhost ~]# kubectl exec -it hello -- hostname
hello

Getting a shell

[root@localhost ~]# kubectl exec -it hello -- bash
root@hello:/# ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Upvotes: 3

itsafire
itsafire

Reputation: 6103

You could use this CMD in your Dockerfile:

CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

This will keep your container alive until it is told to stop. Using trap and wait will make your container react immediately to a stop request. Without trap/wait stopping will take a few seconds.

For busybox based images (used in alpine based images) sleep does not know about the infinity argument. This workaround gives you the same immediate response to a docker stop like in the above example:

CMD exec /bin/sh -c "trap : TERM INT; sleep 9999999999d & wait"

Upvotes: 226

Omar Khaled
Omar Khaled

Reputation: 441

Use this command inside you Dockerfile to keep the container running in your K8s cluster:

  • CMD tail -f /dev/null

Upvotes: 10

Radu Gabriel
Radu Gabriel

Reputation: 3201

  1. In your Dockerfile use this command:

    CMD ["sh", "-c", "tail -f /dev/null"]
    
  2. Build your docker image.

  3. Push it to your cluster or similar, just to make sure the image it's available.
  4. kubectl run debug-container -it --image=<your-image>
    

Upvotes: 78

Lukasz Dynowski
Lukasz Dynowski

Reputation: 13680

My few cents on the subject. Assuming that kubectl is working then the closest command that would be equivalent to the docker command that you mentioned in your question, would be something like this.

$ kubectl run ubuntu --image=ubuntu --restart=Never --command sleep infinity

Above command will create a single Pod in default namespace and, it will execute sleep command with infinity argument -this way you will have a process that runs in foreground keeping container alive.

Afterwords, you can interact with Pod by running kubectl exec command.

$ kubectl exec ubuntu -it -- bash

This technique is very useful for creating a Pod resource and ad-hoc debugging.

Upvotes: 25

Ivan Aracki
Ivan Aracki

Reputation: 5381

There are many different ways for accomplishing this, but one of the most elegant one is:

kubectl run -i --tty --image ubuntu:latest ubuntu-test --restart=Never --rm /bin/sh

Upvotes: 3

Wlodek B.
Wlodek B.

Reputation: 731

The simplest command as it can be for k8s pod manifest to run container forever:

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
  - name: ubuntu
    image: ubuntu:latest
    # Just sleep forever
    command: [ "sleep" ]
    args: [ "infinity" ]

Upvotes: 71

Reese
Reese

Reputation: 1775

I was able to get this to work with the command sleep infinity in Kubernetes, which will keep the container open. See this answer for alternatives when that doesn't work.

Upvotes: 15

Stefan L
Stefan L

Reputation: 1541

In my case, a pod with an initContainer failed to initialize. Running docker ps -a and then docker logs exited-container-id-here gave me a log message which kubectl logs podname didn't display. Mystery solved :-)

Upvotes: 3

Joel B
Joel B

Reputation: 13140

Containers are meant to run to completion. You need to provide your container with a task that will never finish. Something like this should work:

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
  - name: ubuntu
    image: ubuntu:latest
    # Just spin & wait forever
    command: [ "/bin/bash", "-c", "--" ]
    args: [ "while true; do sleep 30; done;" ]

Upvotes: 370

Adrian Mouat
Adrian Mouat

Reputation: 46548

A container exits when its main process exits. Doing something like:

docker run -itd debian

to hold the container open is frankly a hack that should only be used for quick tests and examples. If you just want a container for testing for a few minutes, I would do:

docker run -d debian sleep 300

Which has the advantage that the container will automatically exit if you forget about it. Alternatively, you could put something like this in a while loop to keep it running forever, or just run an application such as top. All of these should be easy to do in Kubernetes.

The real question is why would you want to do this? Your container should be providing a service, whose process will keep the container running in the background.

Upvotes: 76

Related Questions