Docker Healthcheck doesn't work (always unhealthy) - docker

I'm a bit new to docker and it's the first time I'm trying to add healthcheck.
The docker application I'm using is the example from here:
https://docs.docker.com/get-started/02_our_app/
I simply followed the steps to get a container with a service that runs locally on port 3000. I browsed to http://localhost:3000 and it does work.
The Dockerfile before any changes I've made:
# syntax=docker/dockerfile:1
FROM node:12-alpine
RUN apk add --no-cache python g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
And the original command to run the docker:
docker run -dp 3000:3000 getting-started
Then, I tried to add a healthcheck in a few ways.
First way: I changed the Dockerfile as follows, then re-build and re-ran:
# syntax=docker/dockerfile:1
FROM node:12-alpine
HEALTHCHECK --interval=3s --timeout=1s CMD curl --fail http://localhost:3000 || exit 1
RUN apk add --no-cache python g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
Second way: I changed the run command as follows:
docker run -dp 3000:3000 --health-cmd "curl --fail http://localhost:3000 || exit 1" getting-started
In both cases, I checked the health status using docker ps, and after it ended the "health: starting" phase, it always entered the "unhealthy" phase. Never "healthy".
In both cases, I made sure that http://localhost:3000 works and returns HTTP status 200.
While experimenting in all sorts of ways, I tried to remove the || exit 1 part but it did not help. I tried to replace it with || exit 0, and then indeed it displayed "healthy", but that doesn't really mean anything.
Does anyone have any idea what am I doing wrong? I need to do something more complex with healthcheck, but for starters I want to succeed in making it work for a simple thing.
More details:
I'm using Windows 10 Enterprise Version 20H2, Docker version 20.10.7, build f0df350. I'm running the commands from Git Bash.

Related

Docker get-started tutorial, port 3000 does not run the app

I am new to Docker and I am following their official tutorial - https://docs.docker.com/get-started/.
I am trying to start my container with this command - docker run -dp 3000:3000 getting-started.
However, when I am trying to open my browser to http://localhost:3000 I get
I already did try to run it on different port - docker run -dp 3000:80 getting-started, however it redirects me to docker tutrial page and thats not what I want.
I have created a file app/Dockerfile with this content:
# syntax=docker/dockerfile:1
FROM node:12-alpine
RUN apk add --no-cache python3 g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
I can't find the problem and I will be grateful for help.
Not sure if you ever solved this but I had a similar issue as I missed this all important line located in this section:
"If you haven't already done so, open a terminal and go to the app directory with the Dockerfile"
Your Dockerfile, as did mine in my http://localhost/tutorial/our-application/ does not have the
EXPOSE 3000
line at the end, whereas this line indeed appears in the Dockerfile in https://docs.docker.com/get-started/02_our_app/#build-the-apps-container-image (link provided in pbay's answer).
Without that line, the produced container does not expose port 3000, and docker start -dp 3000:(whatever) is bound to fail. [Edit: that's my understanding as a near-absolute beginner, but other people seem to have run that container successfully without that line. Go figure why/how. I'm ready to be enlightened.] In "Docker Desktop" on Windows, you can see in the dashboard that the container exits as soon as it starts.
I added that EXPOSE 3000 line, rebuild and rerun the using the same commands as first time:
docker build -t getting-started .
docker -dp 3000:3000 getting-started
and it now works fine.
(Rant: "If you've created Dockerfiles before, you might see a few flaws in the Dockerfile below" they say. Well this is not a minor flaw -- this is a beginner-discouraging trap. How come ?)

How to run two commands on Dockerfile?

I have to execute two commands on the docker file, but both these commands are attached to the terminal and block the execution from the next.
dockerfile:
FROM sinet/nginx-node:latest
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
RUN git clone https://name:pass#bitbucket.org/joaocromg/front-web-alferes.git
WORKDIR /usr/src/app/front-web-alferes
RUN npm install
RUN npm install bower -g
RUN npm install gulp -g
RUN bower install --allow-root
COPY default.conf /etc/nginx/conf.d/
RUN nginx -g 'daemon off;' & # command 1 blocking
CMD ["gulp watch-dev"] # command 2 not executed
Someone know how can I solve this?
Try creating a script like this:
#!/bin/sh
nginx -g 'daemon off;' &
gulp watch-dev
And then execute it in your CMD:
CMD /bin/my-script.sh
Also, notice your last line would not have worked:
CMD ["gulp watch-dev"]
It needed to be either:
CMD gulp watch-dev
or:
CMD ["gulp", "watch-dev"]
Also, notice that RUN is for executing a command that will change your image state (like RUN apt install curl), not for executing a program that needs to be running when you run your container. From the docs:
The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.
I suggest you try supervisord in this case. http://supervisord.org/
Edit: Here is an dockerized example of httpd and ssh daemon: https://riptutorial.com/docker/example/14132/dockerfile-plus-supervisord-conf
The answer here is that RUN nginx -g 'daemon off;' is intentionally starting nginx in the foreground, which is blocking your second command. This command is intended to start docker containers with this as the foreground process. Running RUN nginx will start nginx, create the master and child nodes and (hopefully) exit with a zero status code. Although as mentioned above, this is not the intended use of run, so a bash script would work best in this case.

How to configure Dockerfile correctly to run on Google Cloud Run?

I'm trying to run a Go app using Docker on Google Cloud Run but I'm getting this error:
Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable. Logs for this revision might contain more information.
I fixed my port to be 8080 as stated in the docs but I think my Dockerfile is incorrect. Does anyone know what I'm missing?
FROM golang:1.12-alpine
RUN apk upgrade -U \
&& apk add \
ca-certificates \
git \
libva-intel-driver \
make \
&& rm -rf /var/cache/*
ENV GOOS linux
ENV GOARCH amd64
ENV CGO_ENABLED=0
ENV GOFLAGS "-ldflags=-w -ldflags=-s"
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN echo $PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
RUN go get -u github.com/cespare/reflex
# RUN reflex -h
# Setup modules after reflex install
ENV GO111MODULE=on \
GOFLAGS="$GOFLAGS -mod=vendor"
WORKDIR /go/src/bitbucket.org/team/app/
COPY . .
CMD [ "go", "run", "cmd/main.go" ]
Dockerfiles don't make your application listen on a specific port number.
The EXPOSE directive in Dockerfile is purely a documentation and doesn't do anything functional.
You have 2 options for a Go app:
Just refactor your code to read the PORT env variable: os.Getenv("PORT") and use it on the HTTP server address you’re starting:
port := os.Getenv("PORT")
http.ListenAndServe(":"+port)
Create a -port flag and read it during the entrypoint of your app in the Dockerfile:
e.g. if you can make go run main.go -port=8080 work, change your dockerfile to:
exec go run main.go -port=$PORT
These will get you what you want.
Ideally you should not use go run inside a container. Just do:
RUN go build -o /bin/my-app ./my/pkg
ENTRYPOINT /bin/my-app
to compile a Go program and use it directly. Otherwise, every time Cloud Run starts your container, you would be re-compiling it from scratch, which is not fast, this will increase your cold start times.
Aside from these you seem to have a lot of inconsistencies in your dockerfile. You set a lot of Go env vars like GOOS GOARCH but you don't actually go build your app (go run is an on-the-fly compilation and doesn't take the linker flags in GOFLAGS into account I believe). Look at sample Go dockerfiles to have a better idea on how to write idiomatic Go dockerfiles.
It seems that you are missing the EXPOSE in your Dockerfile. See https://docs.docker.com/engine/reference/builder/#expose

Go Docker Container Fail: "Exit Code 1"

i'am trying to running my Go Apps in Docker container, but it fail and give error exit code 1. The application works well in my local machine but not in Docker.
Below is my Dockerfile.
FROM golang:1.8 as goimage
RUN go get -u github.com/golang/dep/cmd/dep
COPY . src/github.com/aditmayapada/tryout
WORKDIR src/github.com/aditmayapada/tryout
ENV PORT 9090
RUN dep ensure
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/main
FROM alpine:3.6 as baseimagealp
RUN apk add --no-cache bash
ENV WORK_DIR=/docker/bin
WORKDIR $WORK_DIR
# RUN mkdir src/github.com/aditmayapada/tryout/bin
# WORKDIR src/github.com/aditmayapada/tryout/bin
COPY --from=goimage /go/src/github.com/aditmayapada/tryout/bin ./
ENTRYPOINT /docker/bin/main
EXPOSE 9090
And below is my apps repository that i want to deploy in Docker
https://github.com/aditmayapada/tryout
I have tried to get logs using docker events, and i only get this
Logs
Then i tried to use --logs in docker but its not showing anything.
Am i missing something here? because my apps run well in my local machine... Thank you.
I have briefly looked at your code and found that app could be finished in a case when connection.Ping() return err
https://github.com/aditmayapada/tryout/blob/master/main.go#L44
I recommend adding some logging in this space to identify a point of exit. It seems something is wrong with connection to DB in docker.

Changing RUN to CMD stops the container from working

I am trying to add Glide to my Golang project but I'm not getting my container working. I am currently using:
# create image from the official Go image
FROM golang:alpine
RUN apk add --update tzdata bash wget curl git;
# Create binary directory, install glide and fresh
RUN mkdir -p $$GOPATH/bin
RUN curl https://glide.sh/get | sh
RUN go get github.com/pilu/fresh
# define work directory
ADD . /go
WORKDIR /go/src
RUN glide update && fresh -c ../runner.conf main.go
as per #craigchilds94's post. When I run
docker build -t docker_test .
It all works. However, when I change the last line from RUN glide ... to CMD glide ... and then start the container with:
docker run -it --volume=$(PWD):/go docker_test
It gives me an error: /bin/sh: glide: not found. Ignoring the glide update and directly starting fresh results in the same: /bin/sh fresh: not found.
The end goal is to be able to mount a volume (for the live-reload) and be able to use it in docker-compose so I want to be able to build it, but I do not understand what is going wrong.
This should probably work for your purposes:
# create image from the official Go image
FROM golang:alpine
RUN apk add --update tzdata bash wget curl git;
# Create binary directory, install glide and fresh
RUN go get -u github.com/Masterminds/glide
RUN go get -u github.com/pilu/fresh
# define work directory
ADD . /go
WORKDIR /go/src
ENTRYPOINT $GOPATH/bin/fresh -c /go/src/runner.conf /go/src/main.go
As far as I know you don't need to run the glide update after you've just installed glide. You can check this Dockerfile I wrote that uses glide:
https://github.com/timogoosen/dockerfiles/blob/master/btcd/Dockerfile
and here is the REAMDE: https://github.com/timogoosen/dockerfiles/blob/master/btcd/README.md
This article gives a good overview of the difference between: CMD, RUN and entrypoint: http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/
To quote from the article:
"RUN executes command(s) in a new layer and creates a new image. E.g., it is often used for installing software packages."
In my opinion installing packages and libraries can happen with RUN.
For starting your binary or commands I would suggest use ENTRYPOINT see:"ENTRYPOINT configures a container that will run as an executable." you could use CMD too for running:
$GOPATH/bin/fresh -c /go/src/runner.conf /go/src/main.go
something like this might work, I didn't test this part:
CMD ["$GOPATH/bin/fresh", "-c", "/go/src/runner.conf /go/src/main.go"]

Resources