Permanently change the tomcat port from Dockerfile - docker

I want to run two containers inside a k8s pod.
tomcat exporter ( which runs on port 8080 )
tomcat application ( which also runs on the port 8080 )
As multiple running containers inside a pod cant share a same port , I am looking forward to build a custom tomcat image with a different port ( say 9090 ( default tomcat port is : 8080 ))
This is what the Dockerfile I have used.
cat Dockerfile
FROM tomcat:9.0.34
RUN sed -i 's/8080/9090/' /usr/local/tomcat/conf/server.xml
EXPOSE 9090
After building that image and running a container, I see that 9090 port has been assigned , but I also see 8080 is also still existing.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b66e1e9c3db8 chakilams3/tomcatchangedport:v1 "catalina.sh run" 3 seconds ago Up 2 seconds 8080/tcp, 0.0.0.0:9090->9090/tcp test
I am wondering from where does this 8080/tcp port comes from , even after I have changed all refferences of 8080 to 9090 in the server.xml file
Any thoughts are appreciated.

With lots of effort, I found the solution to change the internal port of tomcat
container
my Dockerfile is
FROM tomcat:7.0.107
RUN sed -i 's/port="8080"/port="4287"/' ${CATALINA_HOME}/conf/server.xml
ADD ./tomcat-cas/war/ ${CATALINA_HOME}/webapps/
CMD ["catalina.sh", "run"]
Here
ADD ./tomcat-cas/war/ ${CATALINA_HOME}/webapps/ part is not necessary unless you want to initially deploy some war files. And also I don't add EXPOSE 4287, because if I did so, the tomcat server not binding to the port 4287 then it always binding to the 8080 default port.
Just build the image and run
docker build -f Dockerfile -t test/tomcat-test:1.0 .
docker run -d -p 4287:4287 --name tomcat-test test/tomcat-test:1.0

Checking the tomcat:9.0.34 Dockerfile in Dockerhub, we can see that it is exposing port 8080. What happens when you use this image as your parent image, is that you inherit this EXPOSE instruction from that image.
Searching through the documentation, there does not seem to exist an "unexpose" instruction in the Dockerfile to undo the EXPOSE 8080 instruction of the parent image.
This should not cause any issue, but if you would like to eliminate it, you could fork the tomcat Dockerfile, remove the EXPOSE instruction and build your own tomcat image.

Related

ASP.NET Core Webapi startup url - Docker-Compose vs. Docker build

I am encountering an interesting difference in startup behaviour when running a simple net6.0 web api built with docker-compose in comparison to being built with docker. The application itself runs in a kubernetes cluster.
Environment
Minikube v1.26.1
Docker Desktop v4.12
Docker Compose v2.10.2
Building with docker-compose
docker-compose.yml
version: "3.8"
services:
web.api:
build:
context: ./../
dockerfile: ./web.API/Dockerfile
The context is set to the parent directory due to some files needed there.
Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build
WORKDIR /src
ENV ASPNETCORE_URLS=http://+:80
COPY Directory.Build.props ./Directory.Build.props
COPY .editorconfig ./.editorconfig
COPY ["webapi/web.API", "web.API/"]
RUN dotnet build "web.API/web.API.csproj" -c Release --self-contained true --runtime alpine-x64
RUN dotnet publish "webapi/web.API.csproj" -c Release -o /app/publish \
--no-restore \
--runtime alpine-x64 \
--self-contained true \
/p:PublishSingleFile=true
FROM mcr.microsoft.com/dotnet/runtime-deps:6.0-alpine
WORKDIR /app
EXPOSE 80
EXPOSE 443
COPY --from=build /app/publish .
ENTRYPOINT ["./web.API"]
This results in the app starting up within the kubernetes cluster with the following logs:
Now listening on: http://[::]:80
Building with docker build
Using the same Dockerfile mentioned earlier with the same build context you can see in the docker-compose.yml, a deployment to k8s results in the following log:
Now listening on: http://localhost:5000
Running the image locally
Running the exact same image from the k8s cluster locally however results in
Now listening on: http://[::]:80
Already tried
As suggested in many posts, I tried setting the environment variable ASPNETCORE_URLS via Dockerfile or k8s deployment.yml- neither of which had an impact on the startup url.
I can't seem to figure out why there is a difference between those 2 ways of building an image.
Update
The only thing that seems to work is to add
builder.WebHost.ConfigureKestrel(option =>{
option.ListenAnyIP(80);
});
to the Program.cs.
Still not sure about the reason behind the behaviour though.
A few things:
I assume that the container already running and working on port 80 (docker run) is stopped before attempting to run docker-compose?
Environment variables can be used in docker-compose.yml file
Ports most likely need to be exposed correctly, which from the Dockerfile and docker-compose.yml seems like it is not?
Environment Variables
First off, before the environmental ENV ASPNETCORE_URLS=http://+:80 is going to be of any use, your docker-compose instance does not define which ports to use, your docker-compose (if trimmed) does not show any ports.
Perhaps because the ports aren't exposed, this means the environmental tries to connect to 80, which fails (already in use/not exposed) and then fails, and somehow connects on 5000.
Alternatively, more likely: it does not really not _see your ENV ASPNETCORE_URLS
You can try environment variables directly in your docker-compose file:
my-service:
image: ${IMAGE_NAME}
environment:
MY_SECRET_KEY: ${MY_SECRET_KEY}
Publishing ports
In docker-compose file you need this, to publish ports:
ports:
- "80"
- "443"
... or
ports:
- "80:80" // "host-port:container-port"
- "443:1234"
Additional information
The keyword EXPOSE\expose in Dockerfile/docker-compose.yml is just informative (comments in a sense), functionally it does not process anything. A port need to be exposed (published) to be used.
So, those EXPOSE 443 & 80 is not telling Docker to use it, perhaps you are running your container for example like this:
This exposes port 80 for it to be available.
docker run -p 127.0.0.1:80:80/tcp image command
In short, use ports keyword in docker-compose.yml.
EDIT:
I read your comment above:
But the app is not accessible in k8s when listening to localhost:5000 even with correct service and container configuration
This indicates what I am trying to say regarding the ports being published or not. Your port 5000 is also not exposed because nothing in your configuration shows that is the case.

Plain .NET 5 project runs in Docker but doesn't reacts to requests

I have a plain .NET 5 project with the default weather forecast. Running locally, it behaves as expected and the call to http://localhost:5000/WeatherForecast gives me the data. However, trying to reach the same address when running in Docker container fails. The only difference I can see between the logs is that they listen to different ports. The setup follows roughly the docs on MSDN.
Locally it is 5000/5001.
info: Microsoft.Hosting.Lifetime[0]
Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://localhost:5000
Containerized it is 80.
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://[::]:80
That surprises me because I published those two ports as shown in the docs. In the Docker desktop client, I can see port: 5000 mentioned (but not 5001). I tried to access Swagger on port 80 with little success (I removed env.IsDevelopment() to make sure that both dev and prod work the same way). I tried both create/start and run. Same result. According to this blog, publishing a port, exposes it too, so no additional expose in the Dockerfile is needed (although I've tested that too).
docker create --publish 5000:5000 --publish 5001:5001 --name dotnet5 dotnet-core-5:webapi
What can I be missing?
The whole Dockerfile looks like this.
from mcr.microsoft.com/dotnet/aspnet:5.0
copy bin/Release/net5.0/publish /app
workdir /app
entrypoint ["dotnet", "WebApi.dll"]
It listens on port 80 in the container because Microsoft set the ASPNETCORE_URLS environment variable in their aspnet Docker images to http://+:80 which overrides your configuration.
To get it to listen on something else, you have to set the ASPNETCORE_URLS variable yourself in your Dockerfile.
To get it to listen on port 5000 and 5001 like you want, you need to add
ENV ASPNETCORE_URLS=http://+:5000;https://+:5001
to your Dockerfile
They set it in the runtime-deps image, which is the base for the runtime image, which is the base for the aspnet image. You can see it here: https://github.com/dotnet/dotnet-docker/blob/d8dc00685a45b7f534e9f68ded50667023ded151/src/runtime-deps/3.1/bullseye-slim/amd64/Dockerfile

Use multiple ports in Docker multistage build

I am using MultiStage in docker for performing tests tasks.
The base image is Selenium which exposes port 4444 and the staged image is nginx for other operations.
The nginx has port 80 exposed.
If I have to expose both ports, only the port80 is exposed, and not 4444 when using
docker run -p 80:80 -p 4444:4444 someimage:2
Dockerfile:
FROM selenium/standalone-firefox AS base
RUN python3 try.py
FROM nginx:alpine
COPY --from=base /report.html /usr/share/nginx/html
You misunderstand how the multistage build works.
Your final image DOES NOT contain everything from every image you specified in your Dockerfile.
It DOES contain everything from the image specified in the last FROM instruction and results of all the commands below.
In you case it contains everything from image nginx:latest and file report.html copied from previous build stage - which means that when you use it to run a container there is nothing listening on port 4444, so exposing it is meaningless.

reportportal.io port to 8080

Im new to docker and reportportal.io and when i do the following command below.
sudo docker-compose -p reportportal up -d --force-recreate
Its trying to create a containter for port 8080 which is being used by jenkins. I received no error at all on my mint machine.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
678d7741cbc4 reportportal/service-analyzer:4.3.0 "/service-analyzer" 50 seconds ago Up 37 seconds 8080/tcp
So what i did is change anything in the yml file that has 8080 to 8083 but still its using that port. How do i get around this?
you need to change only gateway exposed port
- "8080:8080" # HTTP exposed
change it like
- "8080:9090" # HTTP exposed
see codeline here:
https://github.com/reportportal/reportportal/blob/master/docker-compose.yml#L69
Looks like you are not doing the port mapping correctly inside the docker-compose.yml file. Please share the docker-compose file.
It is helpful if share docker file.
Try to run it like this docker-compose -p 8080:8083 -d --force-recreate
refer the following here

Docker Container Listening on http://[::]:80

I am working on setting up two Docker containers using Docker for Windows. A simple node based web app, and a dotnet core API application. I am starting both these containers using "docker-compose up". The node app starts up perfectly and I can hit the exposed URL, however the dotnet app isn't seeming to work.
The output of the docker-compose up command is below:
application.client_1 | INFO: Accepting connections at http://localhost:8080
application.api_1 | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
application.api_1 | No XML encryptor configured. Key {cc83a8ac-e1de-4eb3-95ab-8c69a5961bf9} may be persisted to storage in unencrypted form.
application.api_1 | Hosting environment: Development
application.api_1 | Content root path: /app/application.Api
application.api_1 | Now listening on: http://[::]:80
application.api_1 | Application started. Press Ctrl+C to shut down.
The Docker file looks like the following:
FROM microsoft/dotnet AS build
WORKDIR /app
ENV PORT=8081
COPY application.Api/application.Api.csproj application.Api/
COPY application.Business/application.Business.csproj application.Business/
COPY application.DataAccess/application.DataAccess.csproj application.DataAccess/
COPY application.DataModel/application.DataModel.csproj application.DataModel/
WORKDIR /app/application.Api
RUN dotnet restore
WORKDIR /app/
COPY application.Api/. ./application.Api/
COPY application.Business/. ./application.Business/
COPY application.DataAccess/. ./application.DataAccess/
COPY application.DataModel/. ./application.DataModel/
WORKDIR /app/application.Api
RUN dotnet publish -c Release -o out
FROM microsoft/dotnet AS runtime
WORKDIR /app/application.Api
COPY --from=build /app/application.Api/out .
ENTRYPOINT ["dotnet", "application.Api.dll" ]
EXPOSE $PORT
I am unable to get an IP and thus hit the API url. Any thoughts would be much appreciated as I am pretty new to Docker.
UPDATE 1: Compose YML
version: '3.4'
services:
tonquin.api:
image: application.api
ports:
- 8081:5000
build:
context: .
dockerfile: Dockerfile
tonquin.client:
image: application.client
ports:
- 8080:8080
build:
context: .
dockerfile: ../application.Client/Dockerfile
As they've mentioned it seems your container is running on port 80. So for whatever reason that's the port being exposed.
Maybe the EXPOSE $PORT is not returning 8081 as you expect?
When you run the container, unless you specify where to map it, it will only be available at the container's IP at the exposed port (80 in your case). Find out this container Ip easily by running docker inspect <container_id>
Test your image by doing something like docker run -p 8080:80 yourimage. You'll see that in addition to the port 80 that the image exposes, it is being mapped to your local port 8080 so that http://localhost:8080 should be reachable.
See this in case it helps you
See this answer.
The base dotnet image overrides the default kestrel port. Why, I don't know. Adding the environment declaration to my docker file fixed the problem for me.
It's trying to use the IPv6 protocol on the network interface. Disable IPv6 and restart docker. It also looks like you might have both apps trying to use port 80. You can only serve one item on a given port with a given interface/IP. Try setting the API to use a different port number, like 8080.

Resources