I created a Dockerfile for running Jupyter in Docker.
FROM ubuntu:latest
FROM python:3.7
WORKDIR /app
ADD . /app
RUN pip install -r requirements.txt
CMD ["jupyter", "notebook", "--allow-root", "--ip=0.0.0.0"]
My requirements.txt file looks like this:
jupyter
git+https://github.com/kubernetes-client/python.git
I ran docker build -t hello-jupyter . and it builds fine. Then I ran docker run -p 8888:8888 hello-jupyter and it runs fine.
I'm able to open Jupyter notebook in a web browser (127.0.0.1:8888) when I run the Docker image hello-jupyter.
Now I would like to run Jupyter as a Kubernetes deployment. I created this deployment.yaml file:
apiVersion: v1
kind: Service
metadata:
name: hello-jupyter-service
spec:
selector:
app: hello-jupyter
ports:
- protocol: "TCP"
port: 8888
targetPort: 8888
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-jupyter
spec:
replicas: 4
selector:
matchLabels:
app: hello-jupyter
template:
metadata:
labels:
app: hello-jupyter
spec:
containers:
- name: hello-jupyter
image: hello-jupyter
imagePullPolicy: Never
ports:
- containerPort: 8888
I ran this command in shell:
$ kubectl apply -f deployment.yaml
service/hello-jupyter-service unchanged
deployment.apps/hello-jupyter unchanged
When I check my pods, I see crash loops
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-jupyter-66b88b5f6d-gqcff 0/1 CrashLoopBackOff 6 7m16s
hello-jupyter-66b88b5f6d-q59vj 0/1 CrashLoopBackOff 15 55m
hello-jupyter-66b88b5f6d-spvl5 0/1 CrashLoopBackOff 6 7m21s
hello-jupyter-66b88b5f6d-v2ghb 0/1 CrashLoopBackOff 6 7m20s
hello-jupyter-6758977cd8-m6vqz 0/1 CrashLoopBackOff 13 43m
The pods have crash loop as their status and I'm not able to open Jupyter in a web browser.
What is wrong with the deployment.yaml file? The deployment.yaml file simply runs the Docker image hello-jupyter in four different pods. Why does the Docker image run in Docker but not in Kubernetes pods?
Here is the log of one of my pods:
$ kubectl logs hello-jupyter-66b88b5f6d-gqcff
[I 18:05:03.805 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/traitlets/traitlets.py", line 537, in get
value = obj._trait_values[self.name]
KeyError: 'port'
I do specify a port in my deployment.yaml file. I'm not sure why I get this error in the log.
There are many reasons on getting the CrashLoopBackOff error. In your case, it seems like your deployment file is locked or a lack of resources prevents the container from loading.
As I understood, you've built docker image locally and added it to your local Docker registry. Since imagePullPolicy: Never specified and there is no error ErrImageNeverPull, so there is no problem with your docker registries between your local docker and kubernetes.
You can start by running the command: kubectl describe pod [name] to get more from kubelet.
Unless, try deploying single pod first instead of deployment with 4 replicas to make sure that kubernetes runs your image correctly.
Related
I have a python socketio application that works just fine when run locally. However, when I move it into Docker, external clients are unable to connect and throw this error:
socketio.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
The WebSocket server is really basic and publishes to 0.0.0.0:8080. My client apps listen to localhost:8080. In my Docker container, I've exposed port 8080. I'm guessing that I'm setting up my container incorrectly.:
Dockerfile:
FROM python:latest
WORKDIR /path/to/project
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
docker-compose.yml
version: "3.9"
services:
app:
build: .
working_dir: /path/to/project
stdin_open: true
tty: true
ports:
- "8080:8080"
volumes:
- type: bind
source: .
target: /path/to/project
I start up my container with docker-compose up and I'm using Docker Desktop (if that helps). I use this environment for development so I start my server with python my_server.py. The server starts successfully. What else am I missing?
I've tried the following based on what others have said about this problem online
Explicitly setting 0.0.0.0 to be the host
Using EXPOSE 8080 in my Dockerfile
Set the network mode to host
Your container connectivity appears to be fine.
You have not specified any command to run in your container. In order to ensure your server is actually running on port 8080, you can add a CMD instruction in your Dockerfile or specify cmd in your docker-compose.yaml. This can be done with:
CMD ["python", "my_server.py"]
Or with docker-compose.yaml file as:
version: "3.9"
services:
app:
build: .
working_dir: /path/to/project
stdin_open: true
tty: true
command: python my_server.py #<== this overrides the Dockerfile CMD instruction
ports:
- "8080:8080"
volumes:
- type: bind
source: .
target: /path/to/project
You can learn more about command in docker-compose.yaml here.
That's also the recommended way to develop with docker. Running commands inside running containers for dev work is not the right way. You essentially run docker compose every time you test a new change. That avoids a lot of problems like these where connectivity doesn't work.
I have created a simple django application that has one endpoint /health/live and it returns a success message upon receiving a get request.
I run the application locally with python manage.py runserver on port 8000
I also have a docker-compose and Dockerfile as below:
FROM python
ENV PYTHONUNBUFFERED 1
RUN mkdir /inventory
WORKDIR /inventory
COPY . /inventory
WORKDIR /inventory
RUN pip install -r requirements.txt
and
version: '3'
networks:
kong-net:
name: kong-net
driver: bridge
ipam:
config:
- subnet: 172.1.1.0/24
services:
inventory:
container_name: inventory
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
networks:
kong-net:
ipv4_address: 172.1.1.11
ports:
- "8000:8000"
environment:
DEBUG: 'true'
command: python manage.py runserver 0.0.0.0:8000
I then run docker-compose up (I don't detach it to be able to see the logs)
They both work. I send a get request to http://127.0.0.1:8000/health/live:
based on the logs I see, the request goes through the service running directly on the system and not on the docker container
If I stop the service running directly without docker, and send the request, the request goes through the one deployed on docker
is there a reason this is happening? why the first one takes priority?
And shouldn't I see an error when trying to run the docker container or start the application locally? because they are both listening to port 8000!
I am new in Kubernetes, and I want to run the simple flask program on docker in Kubernetes. The image in docker could work successfully, but when I start the K8s.yaml with kubectl apply -f k8s.yaml and execute minikube service flask-app-service the web result reply fail with ERR_CONNECTION_REFUSED, and pods status Error: ErrImageNeverPull.
app.py:
# flask_app/app/app.py
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello, World!"
if __name__ == '__main__':
app.debug = True
app.run(debug=True, host='0.0.0.0')
Dockerfile:
FROM python:3.9
RUN mkdir /app
WORKDIR /app
ADD ./app /app/
RUN pip install -r requirement.txt
EXPOSE 5000
CMD ["python", "/app/app.py"]
K8s.yaml:
---
apiVersion: v1
kind: Service
metadata:
name: flask-app-service
spec:
selector:
app: flask-app
ports:
- protocol: "TCP"
port: 5000
targetPort: 5000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: flask-app
spec:
selector:
matchLabels:
app: flask-app
replicas: 3
template:
metadata:
labels:
app: flask-app
spec:
containers:
- name: flask-app
image: flask_app:latest
imagePullPolicy: Never
ports:
- containerPort: 5000
After deploying I try to connect to http://127.0.0.1:51145 from a browser, but it fails to connect with an ERR_CONNECTION_REFUSED message. I have a screenshot showing a more detailed Chinese-language error message if that detail is helpful.
update:
After switch imagePullPolicy from never to Always or IfNotPresent, the pod still can't run
I try the docker images command it show the image exist:
But when I pull image with docker pull, it show me the error:
After docker login still not work:
p.s. I follow the website to pratice: https://lukahuang.com/running-flask-on-minikube/
Based on the error in the question:
pods status Error: ErrImageNeverPull.
pod doesn't start because you have imagePullPolicy: Never in your deployment manifest. Which means that if the image is missing, it won't be pulled anyway.
This is from official documentation:
The imagePullPolicy for a container and the tag of the image affect
when the kubelet attempts to pull (download) the specified image.
You need to switch it to IfNotPresent or Always.
See more in image pull policy.
After everything is done correctly, pod status should be running and then you can connect to the pod and get the response back. See the example output:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
ubuntu 1/1 Running 0 4d
Why are you using the same port for all the containers? I don't think that will work. You need to assign different ports to each containers or better still create different instances like 3737:5000, 2020:5000 so the external port can be anything while the internal port remains as 5000. That should work I think
I have been trying to run a Python Django application on Kubernets but not success. The application runs fine in Docker.
This is the yaml Deployment to Kubernets:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
creationTimestamp: "2022-02-06T14:48:45Z"
generation: 1
labels:
app: keyvault
name: keyvault
namespace: default
resourceVersion: "520"
uid: ccf0e490-517f-4102-b282-2dcd71008948
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: keyvault
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: keyvault
spec:
containers:
- image: david900412/keyvault_web:latest
imagePullPolicy: Always
name: keyvault-web-5wrph
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status:
conditions:
- lastTransitionTime: "2022-02-06T14:48:45Z"
lastUpdateTime: "2022-02-06T14:48:45Z"
message: Deployment does not have minimum availability.
reason: MinimumReplicasUnavailable
status: "False"
type: Available
- lastTransitionTime: "2022-02-06T14:48:45Z"
lastUpdateTime: "2022-02-06T14:48:46Z"
message: ReplicaSet "keyvault-6944b7b468" is progressing.
reason: ReplicaSetUpdated
status: "True"
type: Progressing
observedGeneration: 1
replicas: 1
unavailableReplicas: 1
updatedReplicas: 1
This is the docker compose file I'm using to run the image in Docker:
version: "3.9"
services:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
This is the docker file I'm using to run the image in Docker:
FROM python:3.9
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
Kubectl describe pod Output:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 51s default-scheduler Successfully assigned default/keyvault-6944b7b468-frss4 to minikube
Normal Pulled 37s kubelet Successfully pulled image "david900412/keyvault_web:latest" in 12.5095594s
Normal Pulled 33s kubelet Successfully pulled image "david900412/keyvault_web:latest" in 434.2995ms
Normal Pulling 17s (x3 over 49s) kubelet Pulling image "david900412/keyvault_web:latest"
Normal Created 16s (x3 over 35s) kubelet Created container keyvault-web-5wrph
Normal Started 16s (x3 over 35s) kubelet Started container keyvault-web-5wrph
Normal Pulled 16s kubelet Successfully pulled image "david900412/keyvault_web:latest" in 395.5345ms
Warning BackOff 5s (x4 over 33s) kubelet Back-off restarting failed container
Kubectl log pod Does not show anything :(
Thanks for your help.
This is a community wiki answer posted for better visibility. Feel free to expand it.
Based on the comments, the solution should be as shown below.
Remove volumes definition from the Compose file:
version: "3.9"
services:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
ports:
- "8000:8000"
Specify the startup command with CMD for an image in Dockerfile:
FROM python:3.9
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
CMD ["python3","manage.py","runserver"]
Then translate a Docker Compose file to Kubernetes resources. This can be done with using Kompose or another suitable solution.
I am trying to incorporate a python container and a dynamodb container into one stack file to experiment with Docker swarm. I have done tutorials on docker swarm seeing web apps running across multiple nodes before but never built anything independently. I am able to run docker-compose up with no issues, but struggling with swarm.
My docker-compose.yml looks like
version: '3.3'
services:
dynamodb:
image: "amazon/dynamodb-local"
ports:
- "8000:8000"
track-count:
image: "my-app"
links:
- "dynamodb:localhost"
Running docker stack deploy -c docker-compose.yml trial_stack brings up no errors however printing 'hello world' as the first line of python code is not displayed in the terminal. I get the following as CMD line output
Ignoring unsupported options: links
Creating network trial_stack_default
Creating service trial_stack_dynamodb
Creating service trial_stack_track-count
My question is:
1) Why is the deploy service ignoring the links? I have noticed this is repeated in the docs https://docs.docker.com/engine/reference/commandline/stack_deploy/ but unsure if this will cause my stack to fail.
2) Assuming the links issue is fixed, where will any command line output be shown, to confirm the system is running? Currently I only have one node, my local machine, which is the manager.
For reference, my python image is being built by the following Dockerfile:
FROM python:3.8-slim-buster
RUN mkdir /app
WORKDIR /app
RUN pip install --upgrade pip
COPY ./requirements.txt ./
RUN pip install -r ./requirements.txt
COPY / /
COPY /resources/secrets.py /resources/secrets.py
CMD [ "python", "/main.py" ]
You can update docker-compose.yaml to enable tty for the services for which you want to see the stdout on console.
Updated docker-compose.yaml should look like this:
version: '3.3'
services:
dynamodb:
image: "amazon/dynamodb-local"
ports:
- "8000:8000"
track-count:
image: "my-app"
tty: true
links:
- "dynamodb:localhost"
and then when once you have the task deployed, to check service logs you can run:
# get the service name
docker stack services <STACK_NAME>
# display the service logs, edited based on user's suggestion
docker service logs --follow --raw <SERVICE_NAME>