Start SSH daemon in Laravel sail - laravel

I'm using Laravel Sail and have published the Dockerfile (so I can edit it manually). The reason being that I need to use an OpenSSH server on the container itself for a program I'm using.
I am able to install OpenSSH by adding && apt-get install -y openssh-server to the packages section and configure it with the following:
RUN mkdir /var/run/sshd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed 's#session\s*required\s*pam_loginuid.so#session optional pam_loginuid.so#g' -i /etc/pam.d/sshd
EXPOSE 22
The issue though is that it does not start when the container starts.
According to this answer you can add an ENTRYPOINT as follows:
ENTRYPOINT service ssh restart && bash
However you can only have one ENTRYPOINT and Laravel Sail has this by default:
ENTRYPOINT ["start-container"]
I have tried the following:
add /usr/sbin/sshd to the start-container script - it didn't start
add CMD ["/usr/sbin/sshd", "-D"] into the Dockerfile as per this answer - it gave a permission denied error when starting the container

As the php container uses supervisor you can add another application to the config. Reference for the config can be found here.
Example
ssh.ini:
[program:sshd]
command=/usr/sbin/sshd -D

Related

Spring Container on App Service takes a long time to start

I am trying to deploy a spring boot docker container on OpenJDK image into APP service on Azure. What baffles me is the time the web app takes on initial run (only during the initial run). I also see on the KUDU console that the container started up in less than 6 seconds but the APP service ran for more than 200 seconds and fails. Please see the attached screenshot. Has some one faced this issue before?
Edit 1: Adding the Docker File
FROM openjdk:11-jre-slim
LABEL Maintainer="Aravind"
VOLUME /tmp
ENV SSH_PASSWD "root:Docker!"
RUN echo "root:Docker!" | chpasswd
RUN apt-get update && apt-get install -y curl && apt-get install -y --no-install-recommends dialog && apt-get install -y --no-install-recommends openssh-server && apt install sudo
RUN useradd -m -d /home/spring spring && usermod -a -G spring spring
COPY sshd_config /etc/ssh/
RUN mkdir -p /tmp
COPY ssh_setup.sh /tmp
RUN chmod +x /tmp/ssh_setup.sh \
&& (sleep 1;/tmp/ssh_setup.sh 2>&1 > /dev/null)
COPY init.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/init.sh
EXPOSE 8000 2222
CMD ["/usr/sbin/sshd", "-D"]
USER spring:spring
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
EXPOSE 8080:8080
USER root:root
ENTRYPOINT ["init.sh"]
So after long research and help from MS support, Finally figured out the issue. As I said before, it is not related to how the container starts up as the container was starting up in less than 6 seconds.
The issue we noticed is that when the start up fails due to HTTP health-check timeout, the app is starting up with port 80 as the listening port. When it is successful, it starts up with port 8080.
Spring-Boot default listening port is 8080. The fix is to manually add the configuration for the APP service
App Setting Name: WEBSITES_PORT
Value: 8080
The above configuration seems to have fixed the issue and now the time to start is the time taken by the docker container within the app service.

Docker Run bash after wildfly/JBoss startup

I have a Dockerfile:
## SELECT IMAGE
FROM ubuntu:18.04
RUN apt-get update && \
apt-get upgrade -y && \
apt install -y openjdk-11-jdk && \
apt install -y wget
## SET JAVA ENV
ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk-amd64
## COPY CONF FILES TO ROOT
COPY conf/root/ssh/authorized_keys /root/.ssh/authorized_keys
COPY conf/root/subversion/auth /root/.subversion/auth
## INSTALL JBOSS
RUN wget -O /tmp/wildfly-16.0.0.Final.tar.gz \
https://download.jboss.org/wildfly/16.0.0.Final/wildfly-16.0.0.Final.tar.gz && \
tar zxvf /tmp/wildfly-16.0.0.Final.tar.gz -C /opt
## JBOSS CONFIG
RUN sed -i -r 's/jboss.bind.address.management:127.0.0.1/jboss.bind.address.management:0.0.0.0/' \
/opt/wildfly-16.0.0.Final/standalone/configuration/standalone.xml
## CLEAN JOSS
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
EXPOSE 8080 9990
CMD /opt/wildfly-16.0.0.Final/bin/add-user.sh --silent=true admin admin
CMD /opt/wildfly-16.0.0.Final/bin/standalone.sh -b=0.0.0.0
CMD /bin/bash
I want to start wildfly and after it is started I want to have a bash of this container.
The problem is that I will never get to the point where CMD /bin/bash is called because CMD /opt/wildfly-16.0.0.Final/bin/standalone.sh -b=0.0.0.0 is blocking the container with this message:
INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://0.0.0.0:9990/management
INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://0.0.0.0:9990
INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 16.0.0.Final (WildFly Core 8.0.0.Final) started in 2526ms - Started 305 of 531 services (324 services are lazy, passive or on-demand)
I tried to do it the way I wrote above but also remove the CMD /bin/bash line from the Dockerfile and create another Dockerfile which should give me a shell and run those two Dockerfiles with a docker-compose but everytime the wildfly status is blocking my further actions.
You should only have one CMD in your Dockerfile and it should be the command that will run what you want to run within your container: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#cmd. To do what you want you can do a docker container exec -it containerid bash after your container is running.

Securing a localhost port for a Flask/Celery app running locally on 0.0.0.0 in Docker on MacOS

My app has a Flask backend and an Angular/Electron frontend. The app runs locally on Mac Catalina. Flask, Celery and Redis are in separate docker containers, while the frontend is outside Docker. The Flask container is listening on port 0.0.0.0:5078. I've set CORS policy to allow messages from "127.0.0.1:4200" only, sent by the frontend. There's no need for internet connections. The backend containers will be launched by the frontend by emulating a terminal command. I'll install the app remotely on non-technical users' Catalina MacBooks.
Question: According to Docker might be exposing ports to the world, Beware of exposing ports in Docker and Docker not blocked by macOS firewall, this use of 0.0.0.0:5078 is a security threat. How can I resolve this threat, eg by block ing any external connections to this port?
Here's some python 3.8 code
# imports: waitress, flask_cors, blueprint
cors = CORS(blueprint, resources={r"/*": {"origins":["http://127.0.0.1:4200"]}})
if __name__ == "__main__":
serve(flask_app, host= '0.0.0.0', port=5078, threads=8)
Here's the Dockerfile:
FROM python:3.8.3-slim-buster
WORKDIR /app
COPY requirements.txt requirements.txt
ENV BUILD_DEPS="build-essential" \
APP_DEPS="curl libpq-dev"
RUN apt-get update \
&& apt-get install -y ${BUILD_DEPS} ${APP_DEPS} --no-install-recommends \
&& pip install --default-timeout=10000 -r requirements.txt
ARG FLASK_ENV="development"
ENV FLASK_ENV="${FLASK_ENV}" \
FLASK_APP="back5x.api.app" \
PYTHONUNBUFFERED="true"\
FLASK_DEBUG=1
COPY . .
RUN ["chmod", "+x", "/app/docker-entrypoint.sh"]
ENTRYPOINT ["/app/docker-entrypoint.sh"]
EXPOSE 5078
CMD ["python", "main.py"]
and the docker-compose:
version: "3.8"
services:
redis:
# ...
web:
build:
context: "."
args:
- "FLASK_ENV=development"
depends_on:
- "redis"
- "worker"
env_file:
- ".env"
environment:
FLASK_DEBUG: 1
FLASK_APP: back5x.api.app.py
healthcheck:
test: "${DOCKER_HEALTHCHECK_TEST:-curl localhost:5078/healthy}"
...
ports:
- "5078:5078"
restart: "unless-stopped"
volumes:
- ".:/app"
worker: #celery worker
...
volumes:
redis: {}
Tried:
The Docker-based solutions I've found use Linux iptables, eg Disallow egress from Docker containers on Docker for Mac and the above references. So I've added these to the Dockerfile:
RUN apt-get install -y iptables --no-install-recommends #after pip install
RUN iptables -N DOCKER-USER #after COPY . .
RUN iptables -I FORWARD -j DOCKER-USER
RUN iptables -A DOCKER-USER -j RETURN
RUN iptables -I DOCKER-USER -i eth0 ! -s 0.0.0.0 -j DROP
Without the middle three lines, I got an error that DOCKER-USER couldn't be found; with them, that I must run as a root. I've tried a privileged mode and app_cap, but as I'm new to Docker, I haven't got this to work.
I've also looked into defining a rule in Mac's PF firewall to block external connections to the port in question. However, this is not ideal for people who'll be using my app. A similar situation is with installing the paid-for "Little Snitch" app.
Before going this route, could there be a code or Docker-based solution? (Or perhaps there is an appropriate command for launching the backend?)
A working solution is based on the David Maze and Matt's comments and on this question. These are the steps:
Open Docker for Mac, Preferences and Docker Engine. Add "ip": "127.0.0.1" to the json config file.
In the docker-compose, set ports to "127.0.0.1:5078:5078" for the web service.
Leave the Dockerfile and the python code as before: ie, the flask host is still 0.0.0.0
As I checked, messages from Electron's localhost 4201 went through. Also, running netstat -anvp tcp | awk 'NR<3 || /LISTEN/ shows that the insecure port 0.0.0.0.5078 is no longer exposed to the outside.
`

Running a Bash Script from (on Docker Container B) from Docker Container A

I have two Docker Containers configured through a Docker Compose file.
Docker Container A - (teamcity-agent)
Docker Container B - (build-tool)
Both start up fine. But as part of the build process in TeamCity - I would like the Agent (Container A) to run a bash script which is on Docker Container B (Only B can run this script).
I tried to set this up using the SSH build step in Team City, but I get connection refused.
Further reading into it shows that SSH isn't enabled in containers and that I shouldn't really be trying to SSH into a container.
So how can I get Container A to run the script on Container B and see the output of the script on A?
What is the best practice for this?
The only way without modifying the application itself is through SSH. It is completely false you cannot SSH to a container. I use SSH to a database container to run database export inside it.
First be sure openssh-server is installed on B. Then you must setup a passwordless connection between A and B.
Then be sure you link your containers in the docker-compose file so you won't need to expose the SSH port.
Snippet to add in Dockerfile for container B
RUN apt-get install -q -y openssh-server
ADD id_rsa.pub /home/ubuntu/.ssh/authorized_keys
RUN chown -R ubuntu:ubuntu /home/ubuntu/.ssh ; \
chmod 700 /home/ubuntu/.ssh ; \
chmod 600 /home/ubuntu/.ssh/authorized_keys
Also you can run the script outside the containers using docker exec in a crontab in the host. But I think you are not looking for this extreme solution.
I can help you via comments
Regards

Not able to access Kibana running in a Docker container on port 5601

I have built a docker image with the following Docker file.
# gunicorn-flask
FROM devdb/kibana
MAINTAINER John Doe <user.name#gmail.com>
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update
RUN apt-get install -y python python-pip python-virtualenv gunicorn
# Setup flask application
RUN mkdir -p /deploy/app
COPY gunicorn_config.py /deploy/gunicorn_config.py
COPY app /deploy/app
RUN pip install -r /deploy/app/requirements.txt
WORKDIR /deploy/app
EXPOSE 5000 5601 9200
# Start gunicorn
CMD ["/usr/bin/gunicorn", "--config", "/deploy/gunicorn_config.py", "listener:app"]
I am running the container from the image created from this Docker file as follows.
sudo docker run -p 5601:5601 -p 9200:9200 -p 5000:5000 -v /home/Workspace/xits/config/elasticsearch.yml:/opt/elasticsearch/config/elasticsearch.yml -v /home/Workspace/xits/config/kibana.yml:/opt/kibana/config/kibana.yml es-kibana-gunicorn:latest
The issue I am facing is that I cannot access Kibana port 5601 on my host machine. My browser page says ERR_CONNECTION_REFUSED
I am able to access port 5000 though.
I can't figure out why this is.Any help would be greatly appreciated.
The parent Dockerfile devdb/kibana is using a script to start kibana and elasticsearch when the docker container is started. See CMD ["/sbin/my_init"] and the script itself.
When in your own Dockerfile you use the CMD instruction, you override the one from the parents Dockerfiles.
Since your CMD only starts gunicorn, elasticsearch and kibana won't ever be started. That's why there is no response on their respective network ports.
The Docker image you inherits from inherits itself from phusion/baseimage which has its own way of making multiple processes run in Docker containers. I recommend you follow the instructions on their README file to learn how to add your gunicorn to the list of services to start. Basically you would have to define a script named run and add it to your docker image within the /etc/service/<service name>/ directory.
In your Dockerfile, add:
COPY run /etc/service/gunicorn/
and the run script should be something similar to:
#!/bin/bash
cd /deploy/app
/usr/bin/gunicorn --config /deploy/gunicorn_config.py listener:app

Resources