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
Related
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 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 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.
I am having issues with getting data back from a docker-selenium container, via a Flask application (also dockerized).
When I have the Flask application running in one container, I get the following error on http://localhost:5000, which goes to the selenium driver using a Remote driver that is running on http://localhost:4444/wd/hub
The error that is generated is:
urllib.error.URLError: <urlopen error [Errno 99] Cannot assign requested address>
I have created a github repo with my code to test, see here.
My docker-compose file below seems ok:
version: '3.5'
services:
web:
volumes:
- ./app:/app
ports:
- "5000:80"
environment:
- FLASK_APP=main.py
- FLASK_DEBUG=1
- 'RUN=flask run --host=0.0.0.0 --port=80'
command: flask run --host=0.0.0.0 --port=80
# Infinite loop, to keep it alive, for debugging
# command: bash -c "while true; do echo 'sleeping...' && sleep 10; done"
selenium-hub:
image: selenium/hub:3.141
container_name: selenium-hub
ports:
- 4444:4444
chrome:
shm_size: 2g
volumes:
- /dev/shm:/dev/shm
image: selenium/node-chrome:3.141
# image: selenium/standalone-chrome:3.141.59-copernicium
depends_on:
- selenium-hub
environment:
- HUB_HOST=selenium-hub
- HUB_PORT=4444
What is strange is that when I run the Flask application in Pycharm, and the selenium grid is up in docker, I am able to get the data back through http://localhost:5000. The issue is only happening when the Flask app is running inside docker.
Thanks for the help in advance, let me know if you require further information.
Edit
So I amended my docker-compose.yml file to include a network (updated the code in github. As I've had the Flask app code running in debug and in a volume, any update to the code results in a refresh of the debugger.
I ran docker network inspect on the created network, and found the local docker IP address of selenium-hub. I updated the app/utils.py code, in get_driver() to use the IP address in command_executor rather than localhost. Saving, and re-running from my browser results in a successful return of data.
But I don't understand why http://localhost:4444/wd/hub would not work, the docker containers should see each other in the network as localhost, right?
the docker containers should see each other in the network as localhost, right?
No, this is only true when they use the host networking and expose ports through the host.
When you have services interacting with each other in docker-compose (or stack) the services should refer to each other by the service name. E.g. you would reach the hub container at http://selenium-hub:4444/wd/hub. Your Flask application could be reached by another container on the same network at http://web
You may be confused if your default when running docker normally is to use host networking because on the host network selenium-hub is also exposed on the same port 4444. So, if you started a container with host networking it could use http://localhost:4444 just fine there as well.
Could potentially be a port in use issue related to the execution?
See:
Python urllib2: Cannot assign requested address
I'd like to have two Docker containers, which are defined in the same docker-compose.yaml file to be able to share a network and interact with each others' exposed ports. I'm running all of this on Docker for Mac.
In order to do so, I've set up a couple docker containers that are running a tiny Flask server which can either return a "Hello" or make a request to another server (see below for details). So far, I've been unable to allow the two apps to communicate with each other.
What I've tried so far:
exposeing the relevant ports
publishing the ports and mapping them 1:1 with the host
For flask using both localhost and 0.0.0.0 as the --host arg
curl from one container to another (using both localhost:<other_container_port> and 0.0.0.0:<other_container_port>
Using the implicit network as per the docs
Explicit network definition
All of the above examples give me a Connection Refused error, so I feel like I'm missing something basic about Docker networking.
The Networking in Compose doc mentions the following:
When you run docker-compose up, the following happens:
...
A container is created using db’s configuration. It
joins the network myapp_default under the name db.
And their example appears to have all the separate services be able to communicate without any network definitions, which leads me to believe that I probably should not need to define a network either.
Below is my docker-compose.yaml file - all the files can be found at this gist:
version: '3'
services:
receiver:
build: ./app
# Tried with/without expose
expose:
- 3000
# Tried with/without ports
ports:
- 3000:3000
# Tried with/without 0.0.0.0
command: "--host 0.0.0.0 --port 3000"
# Tried with/without explicit network
networks:
- mine
requester:
build: ./app
expose:
- 4000
ports:
- 4000:4000
# This one's ip is 0.0.0.0, so we can access from host
command: "--host 0.0.0.0 --port 4000"
networks:
- mine
networks:
mine: {}
The app.py file:
#app.route("/")
def hello():
return "Hello from {}".format(request.host)
#app.route("/request/<int:port>")
def doPing(port):
location = "http://localhost:{}/".format(port)
return requests.get(location, timeout=5).content
in docker-compose the services that are on same network can access each other by its name, you dont even have to expose the ports to host. so your docker-compose.yaml can be simplified to:
version: '3'
services:
receiver:
build: ./app
command: "--host 0.0.0.0 --port 3000"
requester:
build: ./app
command: "--host 0.0.0.0 --port 4000"
and inside the container requester you can access the other one with
ping receiver
that resolves the name and you can verify the port is also open, for example with netcat
nc -z receiver 3000 -v