Running a Docker container that accept traffic from the host - apache

I have the following config:
Dockerfile
FROM centos
MAINTAINER Eduar Tua <eduartua#gmail.com>
RUN yum -y update && yum clean all
RUN yum -y install httpd && yum clean all
RUN echo "Apache works" >> /var/www/html/index.html
EXPOSE 80
ADD run-apache.sh /run-apache.sh
RUN chmod -v +x /run-apache.sh
CMD ["/run-apache.sh"]
The run-apache.sh script:
#!/bin/bash
rm -rf /run/httpd/* /tmp/httpd*
exec /usr/sbin/apachectl -D FOREGROUND
Then I build the image with:
sudo docker build --rm -t platzi/httpd .
then
sudo docker run -d -p 80:80 platzi/httpd
After that when I try to run the container accepting connections from the host in the 80 port I get this:
67ed31b50133adc7c745308058af3a6586a34ca9ac53299d721449dfa4996657
FATA[0002] Error response from daemon: Cannot start container 67ed31b50133adc7c745308058af3a6586a34ca9ac53299d721449dfa4996657: Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use
Any help?

It is saying port 80 is busy ... run this to see who is using port 80
sudo netstat -tlnp | grep 80 # sudo apt-get install net-tools # to install netstat
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1380/nginx -g daemo
tcp6 0 0 :::80 :::* LISTEN 1380/nginx -g daemo
scroll to far right to see offending PID of process holding port 80 ... its PID 1380 so lets do a process list to see that pid
ps -eaf | grep 1380
root 1380 1 0 11:33 ? 00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
so teardown that offending process to free up the port 80
sudo kill 1380 # if you know the pid ( 1380 for example )
__ or __
sudo fuser -k 80/tcp # just kill whatever pid is using port 80 tcp
If after doing above its still saying busy then probably the process which you killed got auto relaunched in which case you need to kill off its watcher however you can walk up the process tree from netstat output to identify this parent process and kill that too
Here is how to identify the parent pid of a given process pid
ps -eafww
eve 2720 2718 0 07:56 ? 00:00:00 /usr/share/skypeforlinux/skypeforlinux --type=zygote
in above pid is 2720 and its parent will be the next column to right pid 2718 ... there are commands to show a process tree to visualize these relationships
ps -x --forest
or
pstree -p
with sample output of
systemd(1)─┬─ModemManager(887)─┬─{ModemManager}(902)
│ └─{ModemManager}(906)
├─NetworkManager(790)─┬─{NetworkManager}(872)
│ └─{NetworkManager}(877)
├─accounts-daemon(781)─┬─{accounts-daemon}(792)
│ └─{accounts-daemon}(878)
├─acpid(782)
├─avahi-daemon(785)───avahi-daemon(841)
├─colord(1471)─┬─{colord}(1472)
│ └─{colord}(1475)
├─containerd(891)─┬─containerd-shim(1836)─┬─registry(1867)─┬─{registry}(1968)
│ │ │ ├─{registry}(1969)
│ │ │ ├─{registry}(1970)

The error seems pretty clear:
FATA[0002] Error response from daemon: Cannot start container 67ed31b50133adc7c745308058af3a6586a34ca9ac53299d721449dfa4996657: Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use
It says, "address already in use". This means that something on your system -- probably a web server like Apache -- is already listening on port 80. You will either need to:
stop the web server,
select a different host port in the -p argument to docker run or
just drop the -p argument.
Because Docker can't set up the requested port forwarding, it does not start the container.
Options (a) and (b) will both allow the container to bind to port 80 on your host. This is only necessary if you want to access the container from somewhere other than your host.
Option (c) is useful if you only want to access the container from the docker host but do not want to otherwise expose the container on your local network. In this case, you would use the container ip address as assigned by docker, which you can get by running docker inspect and perusing the output, or just running:
docker inspect --format '{{ .NetworkSettings.IPAddress }}' container_id

If you are running Ubuntu, just run
sudo /etc/init.d/apache2 stop
Then reload your Docker Image
docker reload

I found so solution:
$ docker stop container_name
$ docker commit container_name image_name
$ docker rm container_name
then u can create a new container from the image:
$ docker run -d -P --name container_name_the_same_or_new image_name
and now works.

Related

Docker-compose can't start apache server

When i'm running sudo docker-compose up inside my dir, i get this error. I'm trying to make a container, that host a php website, where you can do whoami on it.
Thanks
(13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80
| no listening sockets available, shutting down
| AH00015: Unable to open logs
Dockerfile:
FROM ubuntu:16.04
RUN apt update
RUN apt install -y apache2 php libapache2-mod-php
RUN useradd -d /home/cp/ -m -s /bin/nologin cp
WORKDIR /home/cp
COPY source .
USER cp
ENTRYPOINT service apache2 start && /bin/bash
docker-compose.yml
version: '2'
services:
filebrowser:
build: .
ports:
- '8000:80'
stdin_open: true
tty: true
volumes:
- ./source:/var/www/html
- ./logs:/var/log/apache2
There's a long-standing general rule in Unix-like operating systems that only the root user can open "low" ports 0-1023. Since you're trying to run Apache on the default HTTP port 80, but you're running it as a non-root user, you're getting the "permission denied" error you see.
The absolute easiest answer here is to use a prebuilt image that has PHP and Apache preinstalled. The Docker Hub php image includes a variant of this. You can use a simpler Dockerfile:
FROM php:7.4-apache
# Has Apache, mod-php preinstalled and a correct CMD already,
# so the only thing you need to do is
COPY source /var/www/html
# If you want to run as a non-root user, you can specify
RUN useradd -r -U cp
ENV APACHE_RUN_USER cp
ENV APACHE_RUN_GROUP cp
With the matching docker-compose.yml
version: '3' # version 2 vs 3 doesn't really matter
services:
filebrowser:
build: .
ports:
- '8000:80'
volumes:
- ./logs:/var/log/apache2
If you want to build things up from scratch, the next easiest option would be the Apache User directive: have your container start as root (so it can bind to port 80) but then instruct Apache to switch to the unprivileged user once it's started up. The standard php:...-apache image has an option to do this on its own which I've shown above.

Dockerized apache server not exposing port 80

I am trying to run a React application inside a docker container. My application image was built with the following Dockerfile:
Dockerfile
FROM node:latest
LABEL autor="Ed de Almeida"
RUN apt-get update
RUN apt-get install -y apache2
RUN mkdir /tmp/myapp
COPY . /tmp/myapp
RUN cd /tmp/myapp && npm install
RUN cd /tmp/myapp && npm run build
RUN cd /tmp/myapp/build && cp -Rvf * /var/www/html
RUN cd /var/www && chown -Rvf www-data:www-data html/
EXPOSE 80
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2
ENV APACHE_PID_FILE /var/run/apache2.pid
CMD /usr/sbin/apache2ctl -D FOREGROUND
As you may see, I create a production build, copy it to the standard directory of the Apache server and then run the Apache server. I even exposed port 80, the Apache default port.
I am creating the image with
docker build -t myimage .
and running the container with
docker run -d -p 80:80 --name myapp myimage
I am probably missing something, because I am new to Docker, because the container is there, up and running, but when I point my browser to http://localhost I got nothing.
I entered the container with
docker exec -it myapp bash
and the application is running fine inside it.
Any hints?
When running on windows, Docker will be running on a virtual machine that is running in the backgound. Thus you need to connect to this virtual machine and not to localhost.
You can get the machine ip by running:
docker-machine ip default
This will give you the IP address of the machine, which you can use to connect from the browser.

ERR_EMPTY_RESPONSE for localhost when running Docker

Here's my Dockerfile:
# CentOs base image
FROM centos:centos6.8
# install python, pip, apache and other packages
RUN yum -y update; yum clean all
RUN yum -y install epel-release; yum clean all
RUN yum -y install centos-release-scl; yum clean all
RUN yum -y install python27; yum clean all
RUN yum -y install python-devel.x86_64; yum clean all
RUN yum -y install python-pip; yum clean all
RUN yum -y install gcc; yum clean all
RUN yum -y install httpd httpd-devel mod_ssl; yum clean all
# Make a non root user so I can run mod_wsgi without root
# USER adm
# install Python modules needed by the Python app
COPY requirements.txt /usr/src/app/
RUN pip install --no-cache-dir -r /usr/src/app/requirements.txt
# copy files required for the app to run
COPY . /usr/src/app/
# tell the port number the container should expose
EXPOSE 80
# run the application
# CMD ["mod_wsgi", "start-server run_apache_server.wsgi"]
# CMD ["cat", "/etc/passwd"]
# CMD ["cat", "/etc/group"]
# CMD ["find", "/"]
CMD ["/bin/sh", "-c", "/usr/bin/mod_wsgi-express start-server run_apache_server.wsgi --user adm --group apache"]
I can run the app:
$ docker run -d -P --name myapp jacobirr/pleromatest
And see tcp port 80:
$ docker port myapp
80/tcp -> 0.0.0.0:32769
Here's my requirements.txt:
Flask==0.10.1
Flask-Restless==0.13.1
Flask-SQLAlchemy==0.16
Jinja2==2.7
MarkupSafe==0.18
SQLAlchemy==0.8.2
Werkzeug==0.9.2
gunicorn==17.5
itsdangerous==0.22
mimerender==0.5.4
python-dateutil==2.1
python-mimeparse==0.1.4
requests==1.2.3
six==1.3.0
wsgiref==0.1.2
setuptools==5.4.2
mod_wsgi==4.5.15
Why can't I get to localhost:32769 in the browser? I suspect this is related to:
•the user/group running apache?
•the fact that I'm installing mod_wsgi but it's nowhere on the docker "filesystem" so I have to use mod_wsgi-express?
Update:
'1' Netstat shows:
[root#9003b0d64916 app]# netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 *:irdmi *:* LISTEN
Active UNIX domain sockets (only servers)
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ACC ] STREAM LISTENING 113181 /tmp/mod_wsgi-localhost:8000:0/wsgi.1.0.1.sock
'2' httpd seems to be running in my container:
[root#9003b0d64916 mod_wsgi-localhost:8000:0]# ps aux | grep httpd
root 1 0.0 0.2 64060 5084 ? Ss 21:17 0:00 httpd (mod_wsgi-express) -f /tmp/mod_wsgi-localhost:8000:0/httpd.conf -k start -DFOREGROUND
adm 6 0.0 0.6 350928 13936 ? Sl 21:17 0:00 (wsgi:localhost:8000:0) -f /tmp/mod_wsgi-localhost:8000:0/httpd.conf -k start -DFOREGROUND
adm 7 0.0 0.1 64192 3248 ? S 21:17 0:00 httpd (mod_wsgi-express) -f /tmp/mod_wsgi-localhost:8000:0/httpd.conf -k start -DFOREGROUND
From all your outputs, your httpd / uwsgi process is definitely bound to 8000, and this is the port you need to expose on the container.
This line in netstat, is showing a bind on 8000, and nothing else.
tcp 0 0 *:irdmi *:* LISTEN
It is not obvious here, but if you use the --numeric-ports argument, it will not convert the 8000 into its known port.
In your docker file, again you should
EXPOSE 8000
When launching your container, you can also specify the port to use on the host machine:
docker run -p 8080:8000 --name ...
After this, you should be able to use your browser to hit
localhost:8080 -> container:8000
Add this to your Dockerfile, just before CMD:
WORKDIR /usr/src/app/
Assuming that your start-apache-server file is in that directory. This will help wsgi to find the needed file.

Apache2 Container on BlueMix won't stay up

I've started with IBM's image:
registry.ng.bluemix.net/ibmnode:latest
It's Ubuntu 14.04, I then add Apache2 on, do some file copies of my site, and then EXPOSE 443. Lastly, I invoke a bash script with the following:
#!/bin/bash
set -e
rm -f /usr/local/apache2/logs/httpd.pid
exec /usr/sbin/apache2ctl -DFOREGROUND
When I run the container locally, it works fine and serves up what I need. When BlueMix builds from the Dockerfile, that works without error. Then deploys to a container successfully. Immediately after deploy, the container registers as 'STOPPED'. Restarting brings it up and then back down within a few seconds. 'cf ic logs my-process-id' doesn't show any feedback.
Other things I've tried:
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
Using service apache2 restart
Dockerfile:
FROM registry.ng.bluemix.net/ibmnode:latest
RUN apt-get install -y apache2
RUN apt-get install -y nano
# ADD SSL
RUN a2enmod ssl
RUN a2enmod proxy_http
WORKDIR /var/www/dist
RUN mv ./* /var/www/html
COPY docker/httpd-foreground.sh /usr/local/bin/
EXPOSE 443
CMD ["httpd-foreground.sh"]
httpd-foreground.hs:
#!/bin/bash
set -e
rm -f /usr/local/apache2/logs/httpd.pid
exec /usr/sbin/apache2ctl -DFOREGROUND
What you are trying to do is getting node image, installing apache and overriding the command, and trying to run in the foreground. This is not really a good way to run a apache container on bluemix.
You should do something like this:
1. Follow information in here to pull the httpd image to your local, push the local image to your bluemix name space.
- docker pull httpd:2.4
- docker tag httpd:2.4 registry.ng.bluemix.net//httpd
- docker push registry.ng.bluemix.net//http
2. Once the image is pushed to your namespace, you can create custom image with your Dockerfile, note that I assume you have your website content in public-html folder
FROM registry.ng.bluemix.net//httpd:2.4 COPY ./public-html/
/usr/local/apache2/htdocs/ EXPOSE 80
Build your image
cf ic build --tag myhttp .
Run the container:
cf ic run --name myhttp -p 80 registry.ng.bluemix.net/<yourNameSpace>/myhttp
Bind IP address, using
cf ic bind <IP> myhttp
Access your container with the IP you bound

Redis Daemon not creating a PID file

The Redis startup script is supposed to create a pid file at startup, but I've confirmed all the settings I can find, and no pid file is ever created.
I installed redis by:
$ yum install redis
$ chkconfig redis on
$ service redis start
In my config file (/etc/redis.conf) I checked to make sure these were enabled:
daemonize yes
pidfile /var/run/redis/redis.pid
And in the startup script (/etc/init.d/redis) there is:
exec="/usr/sbin/$name"
pidfile="/var/run/redis/redis.pid"
REDIS_CONFIG="/etc/redis.conf"
[ -e /etc/sysconfig/redis ] && . /etc/sysconfig/redis
lockfile=/var/lock/subsys/redis
start() {
[ -f $REDIS_CONFIG ] || exit 6
[ -x $exec ] || exit 5
echo -n $"Starting $name: "
daemon --user ${REDIS_USER-redis} "$exec $REDIS_CONFIG"
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
echo -n $"Stopping $name: "
killproc -p $pidfile $name
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
These are the settings that came by default with the install. Any idea why no pid file is created? I need to use it for Monit.
(The system is RHEL 6.4 btw)
For those experiencing on Debian buster:
Editing
nano /etc/systemd/system/redis.service
and adding this line below redis [Service]
ExecStartPost=/bin/sh -c "echo $MAINPID > /var/run/redis/redis.pid"
It suppose to look like this:
[Service]
Type=forking
ExecStart=/usr/bin/redis-server /etc/redis/redis.conf
ExecStop=/bin/kill -s TERM $MAINPID
ExecStartPost=/bin/sh -c "echo $MAINPID > /var/run/redis/redis.pid"
PIDFile=/run/redis/redis-server.pid
then:
sudo systemctl daemon-reload
sudo systemctl restart redis.service
Check redis.service status:
sudo systemctl status redis.service
The pid file now should appear.
On my Ubuntu 18.04, I was getting the same error.
Error reported by redis (on /var/log/redis/redis-server.log):
# Creating Server TCP listening socket ::1:6379: bind: Cannot assign requested address
This is because I've disabled IPv6 on this host and redis-server package (version 5:4.0.9-1) for Ubuntu comes with:
bind 127.0.0.1 ::1
Editing /etc/redis/redis.conf and removing the ::1 address solves the problem. Example:
bind 127.0.0.1
Edit: As pointed out in the comments (thanks to #nicholas-vasilaki and #tommyalvarez), by default redis only allows connections from localhost. Commenting all the line, using:
# bind 127.0.0.1 ::1
works, but makes redis listen from the network (not only from localhost).
More details can be found in redis configuration file.
Problem was that the user redis did not have permission to create the pid file (or directory it was in). Fix:
sudo mkdir /var/run/redis
sudo chown redis /var/run/redis
Then I killed and restarted redis and sure enough, there was redis.pid
In CentOs 7 i need to add to the file:
$ vi /usr/lib/systemd/system/redis.service
The next line:
ExecStartPost=/bin/sh -c "echo $MAINPID > /var/run/redis/redis.pid"
And then restart the service:
$ sudo systemctl daemon-reload
$ sudo systemctl restart redis.service
Reference:
CentOs 7: Systemd & PID File
i had a similar problem on Debian Buster, systemd complains about the missing PID file, even though the file exists and redis is running.
on my system the solution using "echo $MAINPID > /run/redis/redis.pid" works by accident, although/because the real PID file is set to /run/redis/redis-server.pid (spot the different filenames!) and on my system the content of /run/redis/redis.pid (the one of the echo) was empty.
in a discussion on systemd-devel#lists.freedesktop.org someone writes:
... systemd will add the MAINPID environment variable any time it
knows what the main PID is. It learns this by reading the PID file ...
So by the time ExecStartPost runs, the main PID may or may not be
known.
having an empty MAINPID environment variable can be even harmful: if you notice the different PID filenames in the suggested solution, and correct it, you may end up in a situation where the PID file written by redis gets overwritten by an empty file. this happened to me, the result was that systemctl start redis.service never finished.
i also noticed that another server with 100% same OS and configuration, but different hardware did not have this problem.
my conclusion is that it just hits some sort of race condition, systemd seems to look for a PID file just a little too early. on my system, whatever command i used as ExecStartPost, it will add enough delay to make the error disappear.
therefore a solution is to use "sleep 1" (sleep 0.1 works too, but 1 second may be on the safe side):
ExecStartPost=/bin/sleep 1
/etc/systemd/system/redis.service now looks like:
[Service]
Type=forking
ExecStart=/usr/bin/redis-server /etc/redis/redis.conf
ExecStartPost=/bin/sleep 1
ExecStop=/bin/kill -s TERM $MAINPID
PIDFile=/run/redis/redis-server.pid
...
an alternative solution is to use "supervised systemd":
/etc/redis/redis.conf:
# If you run Redis from upstart or systemd, Redis can interact with your
# supervision tree. Options:
# supervised no - no supervision interaction
# supervised upstart - signal upstart by putting Redis into SIGSTOP mode
# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
# supervised auto - detect upstart or systemd method based on
# UPSTART_JOB or NOTIFY_SOCKET environment variables
# Note: these supervision methods only signal "process is ready."
# They do not enable continuous liveness pings back to your supervisor.
supervised systemd
override the redis-server.service file using:
systemctl edit redis-server.service
and enter the following:
[Service]
Type=notify
reload the service and the error should be gone:
sudo systemctl restart redis.service
sudo systemctl status redis.service
Here from 2018
Before start, I am on Ubuntu 18.04.I wrote this if anyone comes here
by searching same error.
In my case error is the same but problem is so different. No solutions that proposed here worked.
So I checked logs if they are exist and looked for is there anything useful. Found them on;
cat /var/log/redis/redis-server.log
Searched logs and found that problem is that another service is listening same port.
2963:C 21 Sep 11:07:33.007 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2963:C 21 Sep 11:07:33.008 # Redis version=4.0.9, bits=64, commit=00000000, modified=0, pid=2963, just started
2963:C 21 Sep 11:07:33.008 # Configuration loaded
2974:M 21 Sep 11:07:33.009 # Creating Server TCP listening socket 127.0.0.1:6379: bind: Address already in use
I checked who is listening.
netstat anp | grep 6379
Found it.
tcp6 0 0 :::6379 :::* LISTEN 3036/docker-proxy
It was docker image of redis that installed by another tool
root#yavuz:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a6a94d401700 redis:3.2 "docker-entrypoint.s…" 20 hours ago Up 3 hours 0.0.0.0:6379->6379/tcp incubatorsuperset_redis_1
So I stopped docker image
root#yavuz:~# docker stop incubatorsuperset_redis_1
And redis-server started without problem.
root#yavuz:~# systemctl start redis-server
root#yavuz:~# systemctl status redis-server
● redis-server.service - Advanced key-value store
Active: active (running) since Fri 2018-09-21 11:10:34 +03; 1min 49s ago
Process: 3671 ExecStart=/usr/bin/redis-server /etc/redis/redis.conf (code=exited, status=0/SUCCESS)
For CentOS:
In my case name of Redis server is redis.service, start it edit
systemctl edit redis.service
Add this:
[Service]
ExecStartPost=/bin/sh -c "echo $MAINPID > /var/run/redis/redis.pid"
PIDFile=/var/run/redis/redis.pid
Im my case it create file: /etc/systemd/system/redis.service.d/override.conf
After restart service:
systemctl daemon-reload
systemctl restart redis
And the pid file is:
cat /var/run/redis/redis.pid
=> 19755
sudo nano /etc/redis/redis.conf
Inside the file, find the supervised directive. This directive allows you to declare an init system to manage Redis as a service, providing you with more control over its operation. The supervised directive is set to no by default. Since you are running Ubuntu, which uses the systemd init system, change this to systemd.
My default, Redis does not run as a daemon, and that is why it does not create a pid file. If you look at /etc/redis/redis.conf, it says so explicitly under General.
#By default Redis does not run as a daemon. Use 'yes' if you need it...
daemonize no
So all you need to do is to change it to daemonize yes
For people struggling with getting it to work on Ubuntu 18.04 you need to edit /etc/redis/redis.conf and update the pidfile declaration to following:
pidfile "/var/run/redis/redis-server.pid"
Ubuntu 18. /var/run/redis had the wrong permissions:
drwxr-sr-x 2 redis redis 60 Apr 27 12:22 redis
Changed to 755 (drwxrwxr-x) and the pid file now appears.