How does Kubernetes invoke a Docker image? - docker

I am attempting to run a Flask app via uWSGI in a Kubernetes deployment. When I run the Docker container locally, everything appears to be working fine. However, when I create the Kubernetes deployment on Google Kubernetes Engine, the deployment goes into Crashloop Backoff because uWSGI complains:
uwsgi: unrecognized option '--http 127.0.0.1:8080'.
The image definitely has the http option because:
a. uWSGI was installed via pip3 which includes the http plugin.
b. When I run the deployment with --list-plugins, the http plugin is listed.
c. The http option is recognized correctly when run locally.
I am running the Docker image locally with:
$: docker run <image_name> uwsgi --http 127.0.0.1:8080
The container Kubernetes YAML config is:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: launch-service-example
name: launch-service-example
spec:
replicas: 1
template:
metadata:
labels:
app: launch-service-example
spec:
containers:
- name: launch-service-example
image: <image_name>
command: ["uwsgi"]
args:
- "--http 127.0.0.1:8080"
- "--module code.experimental.launch_service_example.__main__"
- "--callable APP"
- "--master"
- "--processes=2"
- "--enable-threads"
- "--pyargv --test1=3--test2=abc--test3=true"
ports:
- containerPort: 8080
---
kind: Service
apiVersion: v1
metadata:
name: launch-service-example-service
spec:
selector:
app: launch-service-example
ports:
- protocol: TCP
port: 8080
targetPort: 8080
The container is exactly the same which leads me to believe that the way the container is invoked by Kubernetes may be causing the issue. As a side note, I have tried passing all the args via a list of commands with no args which leads to the same result. Any help would be greatly appreciated.

It is happening because of the difference between arguments processing in the console and in the configuration.
To fix it, just split your args like that:
args:
- "--http"
- "127.0.0.1:8080"
- "--module code.experimental.launch_service_example.__main__"
- "--callable"
- "APP"
- "--master"
- "--processes=2"
- "--enable-threads"
- "--pyargv"
- "--test1=3--test2=abc--test3=true"

Related

How to pass arguments in kubernetes to start a rq-worker container

I'm working on a microservice architectural project in which I use rq-workers. I have used docker-compose file to start and connect the rq-worker with redis successfully but I'm not sure how to replicate it in kubernetes. No matter whatever I try with command and args, I'm thrown a status of Crashloopbackoff. Please guide me as to what I'm missing.Below are my docker-compose and rq-worker deployment files.
rq-worker and redis container config:
...
rq-worker:
build: ./simba-app
command: rq worker --url redis://redis:6379 queue
depends_on:
- redis
volumes:
- sharedvolume:/simba-app/app/docs
redis:
image: redis:4.0.6-alpine
ports:
- "6379:6379"
volumes:
- ./redis:/data
...
rq-worker.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: rq-worker
labels:
app: rq-worker
spec:
selector:
matchLabels:
app: rq-worker
template:
metadata:
labels:
app: rq-worker
spec:
containers:
- name: rq-worker
image: some-image
command: ["/bin/sh", "-c"]
#command: ["rqworker", "--url", "redis://redis:6379", "queue"]
args:
- rqworker
- --url
- redis://redis:6379
- queue
imagePullSecrets:
- name: regcred
---
Thanks in advance!
Edit:
I checked the logs using kubectl logs and found the following logs:
Error 99 connecting to localhost:6379. Cannot assign requested address.
First of all, I'm using the 'service name' and not 'localhost' in my code to connect rq and redis. No idea why I'm seeing 'localhost' in my logs.
(Note: The kubernetes service name for redis is same as that used in my docker-compose file)
redis-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
labels:
app: redis
spec:
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:4.0.6-alpine
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
type: ClusterIP
selector:
app: redis
ports:
- port: 6379
targetPort: 6379
You do not need the /bin/sh -c wrapper here. Your setup reads the first args: word, rqworker, and parses it as a shell command, and executes it; the remaining words are lost.
The most straightforward thing to do is to make your command, split into words as-is, as the Kubernetes command:
containers:
- name: rq-worker
image: some-image
command:
- rqworker
- --url
- redis://redis:6379
- queue
(This matches the commented-out string in your example.)
A common Docker pattern is to use an ENTRYPOINT to do first-time setup and to make CMD be a complete shell command that's run at the end of the setup script. In Kubernetes, command: overrides Docker ENTRYPOINT; if your image has this pattern, then you need to not use a command:, but instead to put this command as you have it as args:.
The only time you do need an sh -c wrapper is in unusual cases where you need to run multiple commands, expand environment variables, or otherwise use shell-only features. In this case the command itself must be in a single word in the command: or args:.
command:
- /bin/sh
- -c
- rqworker --url redis://redis:6379 queue

Kubernetes - minikube service connection timeout

I have a Docker environment with 3 containers: nginx, PHP with Laravel and a MySQL database. It works fine, and I'm now trying to learn Kubernetes.
I was hoping to create a deployment and a service just for the nginx container to make it simple to start with:
Here is the deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: toolkit-app-deployment
spec:
replicas: 1
selector:
matchLabels:
container: toolkit-server
template:
metadata:
labels:
container: toolkit-server
spec:
containers:
- name: toolkit-server
image: my/toolkit-server:test
ports:
- containerPort: 8000
imagePullSecrets:
- name: my-cred
Here is the service.yaml:
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
selector:
container: toolkit-server
ports:
- protocol: "TCP"
port: 80
targetPort: 8000
type: LoadBalancer
And just incase it's needed, here is the nginx part of the docker-compose.yaml:
version: "3.8"
services:
server:
build:
context: .
dockerfile: dockerfiles/nginx.dockerfile
ports:
- "8000:80"
volumes:
- ./src:/var/www/html
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
container_name: toolkit-server
The deployment is created successfully and I can see that 1/1 pods are running.
However when I run minikube service backend, the URL I get just times out.
I was expecting to see some sort of nginx page, maybe an nginx error - but with a time out I'm not sure what the next step is.
I'm brand new to Kubernetes to theres a good chance I've messed the ports up or something basic. Any help appreciated.
Edit:
As advised by #david-maze I changed the following in the deployment.yaml:
ports:
- containerPort: 80
And the following in service.yaml:
targetPort: 80
This gave me an nginx error page when viewed in the browser, as expected, but crucially no longer times out.
This is a community wiki answer posted for better visibility. Feel free to expand it.
As discussed in the comments the issue was due to wrong port configuration.
TargetPort is the port on which the service will send requests to, that your pod will be listening on. Your application in the container will need to be listening on this port also.
ContainerPort defines the port on which app can be reached out inside the container.
So in your use case the deployment should have:
ports:
- containerPort: 80
and the service:
targetPort: 80
This will make the connection not to timeout anymore.

Need help running two OS containers in a single pod on kubernetes

I'm still new to Kubernetes. I'm trying to run a ubuntu container and a linux kali container within the same pod on kubernetes. I also need those two containers to be able to be accessed from a browser. My approach right now is using ubuntu and kali docker image with VNC installed.
Here are the docker image that I'm trying to use:
https://hub.docker.com/r/consol/ubuntu-xfce-vnc (Ubuntu image)
https://hub.docker.com/r/jgamblin/kalibrowser-lxde (Kali image)
Here is the YAML file for creating the pod:
apiVersion: v1
kind: Pod
metadata:
name: training
labels:
app: training
spec:
containers:
- name: kali
image: jgamblin/kalibrowser-lxde
ports:
- containerPort: 6080
- name: centos
image: consol/centos-xfce-vnc
ports:
- containerPort: 5901
Here's the problem. When I run the pod with those 2 containers, only the Kali container is having issue running, cause it to keep on restarting.
May I know how I can achieve this?
You can add a simple sleep command to be executed inside then container to keep it running, for example:
apiVersion: v1
kind: Pod
metadata:
name: training
labels:
app: training
spec:
containers:
- name: kali
image: jgamblin/kalibrowser-lxde
ports:
- containerPort: 6080
command: ["bash", "-c"]
args: ["sleep 500"]
- name: centos
image: consol/centos-xfce-vnc
ports:
- containerPort: 5901`
This way the pod will be in running state:
kubectl get pod
NAME READY STATUS RESTARTS AGE
training 2/2 Running 0 81s
jgamblin/kalibrowser-lxde image require tty (display) allocation.
You can see an example command on docker hub page.
Then you should allow it in your Pod manifest:
apiVersion: v1
kind: Pod
metadata:
name: training
labels:
app: training
spec:
containers:
- name: kali
image: jgamblin/kalibrowser-lxde
ports:
- containerPort: 6080
tty: true
- name: centos
image: consol/centos-xfce-vnc
ports:
- containerPort: 5901
Put tty: true in kali container declaration.

Running python script after container is up (Kubernetes)

I'm using the following docker image: https://github.com/budtmo/docker-android It's Docker image for Android emulators.
I'm run It using Kubernetes with the following deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: android-deployment
spec:
selector:
matchLabels:
app: android-emulator
replicas: 10
template:
metadata:
labels:
app: android-emulator
spec:
containers:
- name: android-emulator
image: budtmo/docker-android-x86-8.1
ports:
- containerPort: 6080
- containerPort: 5554
- containerPort: 5555
env:
- name: DEVICE
value: "Samsung Galaxy S8"
After the container is running its automatic start the Android emulator (don't know exactly how).
I need to run python script automatic after the container is up for each running container,
How can I do it? What should I change in my deployment file?
You could simply create a Dockerfile to build your own image from the budtmo/docker-android-x86-8.1 base image and deploy this. Within the Dockerfile you define the start command or entrypoint.
UPDATE
I think I understand, correct me, if I am wrong: You want run your python script against the Android emulator running in Kubernetes.
As I said, I am not really firm with Kubernetes but couldn't you run the Android emulator as an init container, and the python script itself in the "main" container?
Like described here: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/

Minikube services work when run from command line, but applying through YAML doesn't work

Heres image of my Kubernetes services.
Todo-front-2 is working instance of my app, which I deployed with command line:
kubectl run todo-front --image=todo-front:v7 --image-pull-policy=Never
kubectl expose deployment todo-front --type=NodePort --port=3000
And it's working great. Now I want to move on and use todo-front.yaml file to deploy and expose my service. Todo-front service refers to my current try on it. My deployment file looks like this:
kind: Deployment
apiVersion: apps/v1
metadata:
name: todo-front
spec:
replicas: 1
selector:
matchLabels:
app: todo-front
template:
metadata:
labels:
app: todo-front
spec:
containers:
- name: todo-front
image: todo-front:v7
env:
- name: REACT_APP_API_ROOT
value: "http://localhost:12000"
imagePullPolicy: Never
ports:
- containerPort: 3000
---
kind: Service
apiVersion: v1
metadata:
name: todo-front
spec:
type: NodePort
ports:
- port: 3000
targetPort: 3000
selector:
app: todo-front
I deploy it using:
kubectl apply -f deployment/todo-front.yaml
Here is the output
But when I run
minikube service todo-front
It redirects me to URL saying "Site can't be reached".
I can't figure out what I'm doing wrong. Ports should be ok, and my cluster should be ok since I can get it working by only using command-line without external YAML files. Both deployments are also using the same docker-image. I have also tried changing all ports now "3000" to something different, in case they clash with existing deployment todo-front-2, no luck.
Here is also a screenshot of pods and their status:
Anyone with more experience with Kube and Docker cares to take a look? Thank you!
You can run below commands to generate the yaml files without applying it to the cluster and then compare it with the yamls you manually created and see if there is a mismatch. Also instead of creating yamls manually yourself you can apply the generated yamls itself.
kubectl run todo-front --image=todo-back:v7 --image-pull-policy=Never --dry-run -o yaml > todo-front.yaml
kubectl expose deployment todo-front --type=NodePort --port=3000 --dry-run -o yaml > todo-depoloyment.yaml

Resources