ecs-cli stuck creating containers - docker-compose

I'm trying to get a working Docker environment on AWS using the ecs-cli command line.
I have a working local Docker environment using Dockerfiles, docker-compose.yml, a .env file, and a entrypoint.sh scripts. The containers are an apache webserver running PHP and a bunch of extensions, and a MySQL db.
Skeleton file structure is like this:
./db <-- mounted by db container for persistence
./docker
./docker/database
./docker/database/Dockerfile
./docker/database/dump.sql
./docker/webserver
./docker/webserver/apache-config.conf
./docker/webserver/Dockerfile
./docker/webserver/entrypoint.sh
./docker-compose.yml
./web <!-- mounted by web server, contains all public web code
Here's the 2 Docker files:
./docker/database/Dockerfile
FROM mysql:5.6
ADD dump.sql /docker-entrypoint-initdb.d
./docker/webserver/Dockerfile
FROM php:5.6-apache
RUN apt-get update
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
RUN apt-get install -y zlib1g-dev nodejs gdal-bin
RUN npm install -g topojson
RUN docker-php-ext-install mysql mysqli pdo pdo_mysql zip
RUN pecl install dbase
RUN docker-php-ext-enable dbase
COPY apache-config.conf /etc/apache2/sites-enabled/000-default.conf
RUN a2enmod rewrite headers
RUN service apache2 restart
COPY entrypoint.sh /entrypoint.sh
RUN chmod 0755 /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh", "apache2-foreground"]
entrypoint.sh creates some directories in the web directory for apache to write into:
./docker/webserver/entrypoint.sh
#!/bin/sh
mkdir /var/www/html/maps
chown www-data /var/www/html/maps
chgrp www-data /var/www/html/maps
exec "$#"
Here's the docker-compose.yml
version: '2'
services:
webserver:
image: ACCOUNT_NUMBER.dkr.ecr.eu-west-1.amazonaws.com/project/project-webserver
ports:
- "8080:80"
volumes:
- ./web:${APACHE_DOC_ROOT}
links:
- db
environment:
- HTTP_ROOT=http://${DOCKER_HOST_IP}:${DOCKER_HOST_PORT}/
- PHP_TMP_DIR=${PHP_TMP_DIR}
- APACHE_LOG_DIR=${APACHE_LOG_DIR}
- APACHE_DOC_ROOT=${APACHE_DOC_ROOT}/
- SERVER_ADMIN_EMAIL=${SERVER_ADMIN_EMAIL}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
env_file: .env
db:
user: "1000:50"
image: ACCOUNT_NUMBER.dkr.ecr.eu-west-1.amazonaws.com/project/project-database
ports:
- "4406:3306"
volumes:
- ./db:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
env_file: .env
To build the images referenced there I:
Created AWS IAM user with Admin permission and set keys in ~/.aws/credentials under a profile name, then set-up local ENV using
export AWS_PROFILE=my-project-profile
Then built the images locally as follows:
docker/webserver $ docker build -t ACCOUNT_NUMBER.dkr.ecr.eu-west-1.amazonaws.com/project/project-webserver .
docker/database $ docker build -t ACCOUNT_NUMBER.dkr.ecr.eu-west-1.amazonaws.com/project/project-database .
Got docker logged into ECR (running the docker login command echo'd to std-out):
$aws ecr get-login --no-include-email
Created the repos:
$ aws ecr create-repository --repository-name project/project-webserver
$ aws ecr create-repository --repository-name project/project-database
Pushed the images:
$docker push ACCOUNT_NUMBER.dkr.ecr.eu-west-1.amazonaws.com/project/project-webserver
$docker push ACCOUNT_NUMBER.dkr.ecr.eu-west-1.amazonaws.com/project/project-database
Checked they are there:
$ aws ecr describe-images --repository-name project/project-webserver
$ aws ecr describe-images --repository-name project/project-database
All looks fine.
Created an EC2 key-pair in the same region
$ecs-cli configure --region eu-west-1 --cluster project
$ cat ~/.ecs/config
Tried running them on ECS:
$ecs-cli up --keypair project --capability-iam --size 1 --instance-type t2.micro --force
But if I open port 22 in the security group of the resulting EC2 instance and SSH in I can see the agent container running, but no others:
[ec2-user#ip-10-0-0-122 ~]$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d011f1402c26 amazon/amazon-ecs-agent:latest "/agent" 8 minutes ago Up 8 minutes ecs-agent
I don't see anything bad in the logs for the agent
[ec2-user#ip-10-0-1-102 ~]$ docker logs ecs-agent
2017-09-22T13:32:55Z [INFO] Loading configuration
2017-09-22T13:32:55Z [INFO] Loading state! module="statemanager"
2017-09-22T13:32:55Z [INFO] Event stream ContainerChange start listening...
2017-09-22T13:32:55Z [INFO] Registering Instance with ECS
2017-09-22T13:32:55Z [INFO] Registered! module="api client"
2017-09-22T13:32:55Z [INFO] Registration completed successfully. I am running as 'arn:aws:ecs:eu-west-1:248221388880:container-instance/ba24ead4-21a5-4bc7-ba9f-4d3ba0f29c6b' in cluster 'gastrak'
2017-09-22T13:32:55Z [INFO] Saving state! module="statemanager"
2017-09-22T13:32:55Z [INFO] Beginning Polling for updates
2017-09-22T13:32:55Z [INFO] Event stream DeregisterContainerInstance start listening...
2017-09-22T13:32:55Z [INFO] Initializing stats engine
2017-09-22T13:32:55Z [INFO] NO_PROXY set:169.254.169.254,169.254.170.2,/var/run/docker.sock
2017-09-22T13:33:05Z [INFO] Saving state! module="statemanager"
2017-09-22T13:44:50Z [INFO] Connection closed for a valid reason: websocket: close 1000 (normal): ConnectionExpired: Reconnect to continue
I guess I need to figure out why those containers aren't initalising, but where do I look and, better still, what do I need to do next to get this to work?

In case anyone else runs adrift here, the missing incantations were
$ ecs-cli compose create
which builds an ECS task definition from your compose file (assuming it is compatible...)
and
$ecs-cli compose run
which will build and run the containers on the remote EC2 machine.
SSH'ing to the remote machine and doing a "docker ps -a" should show the containers running. Or "docker logs [container_name]" to see what went wrong...

Related

Docker Volume Data is not Persistent

I want to create two Docker volumes and have their data be persistent. I run sudo docker compose up -d, post some data to my website (text that is stores in a sqlite database and an image stored in the filesystem), then run sudo docker compose down. When I run sudo docker compose up -d again, all the data I posted is gone. With the following configs, I expect the data to still be present.
Dockerfile:
FROM python:3.9.16-buster
RUN pip install --upgrade pip
# The Debian/Buster default is to disable the password.
RUN adduser nonroot
RUN mkdir /home/site/ && chown -R nonroot:nonroot /home/site
RUN chown -R nonroot:nonroot /var/log/site
# two volumes created
VOLUME /home/site/db /home/site/static
WORKDIR /home/site
USER nonroot
# folders ./site/static and ./site/db exist in my host directory
COPY --chown=nonroot:nonroot . .
CMD ["python", "./site/main.py"]
compose.yaml:
services:
site:
build: flask
restart: always
ports:
- '8081:8081'
volumes:
- site_db:/home/site/db # same path as the volumes created in the Dockerfile
- site_static:/home/site/static
command: gunicorn -w 1 -t 3 -b 0.0.0.0:8081 --chdir ./site main:app
volumes:
site_db: # I find it odd these volumes keys don't have values, but that's what I have see other people do
site_static:
docker compose up and docker compose down delete my volumes.
docker compose start and docker compose stop do NOT delete my volumes.
Through the Flask app, check where you are uploading the files to, as well as where the sqlite3 db file is. If these paths do not align with the volumes paths, data will not persist.

What is the best way to Dockerize a Play2-Scala application?

For the first case, I followed a blog post and it's recommended adding Java and Docker plugins in the build.sbt file like:
enablePlugins(JavaAppPackaging)
enablePlugins(DockerPlugin)
dockerBaseImage := "openjdk:8"
dockerEntrypoint := Seq("bin/test", "-Denv=dev")
however, it seems to build an unstable image, the container fails to start with an error:
Oops, cannot start the server.
java.nio.file.AccessDeniedException: /opt/docker/RUNNING_PID
at sun.nio.fs.UnixException.translateToIOException(UnixException.java:84)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
at sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:214)
at java.nio.file.spi.FileSystemProvider.newOutputStream(FileSystemProvider.java:434)
at java.nio.file.Files.newOutputStream(Files.java:216)
at play.core.server.ProdServerStart$.createPidFile(ProdServerStart.scala:148)
at play.core.server.ProdServerStart$.start(ProdServerStart.scala:46)
at play.core.server.ProdServerStart$.main(ProdServerStart.scala:30)
at play.core.server.ProdServerStart.main(ProdServerStart.scala)
Can someone help me out on this or on using a Dockerfile instead.
I managed to figure out using Dockerfile; I wrote a Dockerfile in the root directory, the use docker build command
FROM openjdk:8-jdk
#Add build artifacts into stage dir
ADD target/universal/stage stage
EXPOSE 9000
CMD ["stage/bin/play2_app", "-Dplay.http.secret.key=abcdef12345"]
Then build the image:
$ docker build -t play2-test-app:v1 .
Run the docker image locally
$ docker run -d --name play2-test-container -p 9000:9000 [images id]
First ensure the container is running by listing all running containers:
$ docker ps
View your app on browser at:
localhost:9000

Why is postgres container ignoring /docker-entrypoint-initdb.d/* in Gitlab CI

Gitlab CI keeps ignoring the sql-files in /docker-entrypoint-initdb.d/* in this project.
here is docker-compose.yml:
version: '3.6'
services:
testdb:
image: postgres:11
container_name: lbsn-testdb
restart: always
ports:
- "65432:5432"
volumes:
- ./testdb/init:/docker-entrypoint-initdb.d
here is .gitlab-ci.yml:
stages:
- deploy
deploy:
stage: deploy
image: debian:stable-slim
script:
- bash ./deploy.sh
The deployment script basically uses rsync to deploy the content of the repository to to the server via SSH:
rsync -rav --chmod=Du+rwx,Dgo-rwx,u+rw,go-rw -e "ssh -l gitlab-ci" --exclude=".git" --delete ./ "gitlab-ci#$DEPLOY_SERVER:test/"
and then ssh's into the server to stop and restart the container:
ssh "gitlab-ci#$DEPLOY_SERVER" "cd test && docker-compose down && docker-compose up --build --detach"
This all goes well, but when the container starts up, it is supposed to run all the files that are in /docker-entrypoint-initdb.d/* as we can see here.
But instead, when doing docker logs -f lbsn-testdb on the server, I can see it stating
/usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
and I have no clue, why that happens. When running this container locally or even when I ssh to that server, clone the repo and bring up the containers manually, it all goes well and parses the sql-files. Just not when the Gitlab CI does it.
Any ideas on why that is?
This has been easier than I expected, and fatally nothing to do with Gitlab CI but with file permissions.
I passed --chmod=Du+rwx,Dgo-rwx,u+rw,go-rw to rsync which looked really secure because only the user can do stuff. I confess that I propably copypasted it from somewhere on the internet. But then the files are mounted to the Docker container, and in there they have those permissions as well:
-rw------- 1 1005 1004 314 May 8 15:48 100-create-database.sql
On the host my gitlab-ci user owns those files, they are obviously also owned by some user with ID 1005 in the container as well, and no permissions are given to other users than this one.
Inside the container the user who does things is postgres though, but it can't read those files. Instead of complaining about that, it just ignores them. That might be something to create an issue about…
Now that I pass --chmod=D755,F644 it looks like that:
-rw-r--r-- 1 1005 1004 314 May 8 15:48 100-create-database.sql
and the docker logs say
/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/100-create-database.sql
Too easy to think of in the first place :-/
If you already run the postgres service before, the init files will be ignored when you restart it so try to use --build to build the image again
docker-compose up --build -d
and before you run again :
Check the existing volumes with
docker volume ls
Then remove the one that you are using for you pg service with
docker volume rm {volume_name}
-> Make sure that the volume is not used by a container, if so then remove the container as well
I found this topic discovering a similar problem with PostgreSQL installation using the docker-compose tool.
The solution is basically the same. For the provided configuration:
version: '3.6'
services:
testdb:
image: postgres:11
container_name: lbsn-testdb
restart: always
ports:
- "65432:5432"
volumes:
- ./testdb/init:/docker-entrypoint-initdb.d
Your deployment script should set 0755 permissions to your postgres container volume, like chmod -R 0755 ./testdb in this case. It is important to make all subdirectories visible, so chmod -R option is required.
Official Postgres image is running under internal postgres user with the UID 70. Your application user in the host is most likely has different UID like 1000 or something similar. That is the reason for postgres init script to miss installation steps due to permissions error. This issue appears several years, but still exist in the latest PostgreSQL version (currently is 12.1)
Please be aware of security vulnerability when having readable for all init files in the system. It is good to use shell environment variables to pass secrets into the init scrip.
Here is a docker-compose example:
postgres:
image: postgres:12.1-alpine
container_name: app-postgres
environment:
- POSTGRES_USER
- POSTGRES_PASSWORD
- APP_POSTGRES_DB
- APP_POSTGRES_SCHEMA
- APP_POSTGRES_USER
- APP_POSTGRES_PASSWORD
ports:
- '5432:5432'
volumes:
- $HOME/app/conf/postgres:/docker-entrypoint-initdb.d
- $HOME/data/postgres:/var/lib/postgresql/data
Corresponding script create-users.sh for creating users may looks like:
#!/bin/bash
set -o nounset
set -o errexit
set -o pipefail
POSTGRES_USER="${POSTGRES_USER:-postgres}"
POSTGRES_PASSWORD="${POSTGRES_PASSWORD}"
APP_POSTGRES_DB="${APP_POSTGRES_DB:-app}"
APP_POSTGRES_SCHEMA="${APP_POSTGRES_SCHEMA:-app}"
APP_POSTGRES_USER="${APP_POSTGRES_USER:-appuser}"
APP_POSTGRES_PASSWORD="${APP_POSTGRES_PASSWORD:-app}"
DATABASE="${APP_POSTGRES_DB}"
# Create single database.
psql --variable ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --command "CREATE DATABASE ${DATABASE}"
# Create app user.
psql --variable ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --command "CREATE USER ${APP_POSTGRES_USER} SUPERUSER PASSWORD '${APP_POSTGRES_PASSWORD}'"
psql --variable ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --command "GRANT ALL PRIVILEGES ON DATABASE ${DATABASE} TO ${APP_POSTGRES_USER}"
psql --variable ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --dbname "${DATABASE}" --command "CREATE SCHEMA ${APP_POSTGRES_SCHEMA} AUTHORIZATION ${APP_POSTGRES_USER}"
psql --variable ON_ERROR_STOP=1 --username "${POSTGRES_USER}" --command "ALTER USER ${APP_POSTGRES_USER} SET search_path = ${APP_POSTGRES_SCHEMA},public"

Networking using docker-compose in docker executor in circleci

this is a circleci question I guess.
I am quite happy with circleci but now I ran into a problem and I don't know what I'm doing wrong.
Maybe this is something very easy, but I don't see the it.
In short
I can't make containers talk to each other on circleci.
Problem
Basically what I wanted to do is start a server container and a client container, and then let them talk to each other.
I created a minimal example here: https://github.com/mRcSchwering/circleci-integration-test
The README.md basically explains the desired outcome.
I have a .circleci/config.yml like this:
version: 2
jobs:
build:
docker:
- image: docker:18.03.0-ce-git
steps:
- checkout
- setup_remote_docker
- run:
name: Install docker-compose
command: |
apk --update add py2-pip
/usr/bin/pip2 install docker-compose
docker-compose --version
- run:
name: Start Container
command: |
docker-compose up -d
docker-compose ps
- run:
name: Let client talk to server
command: |
docker-compose run client psql -h server -p 5432 -U postgres -c "\l"
In a docker container, docker-compose is installed, which is then used to start a server and a client (postgres here). In the last step I am telling the client to query the server. However, it cannot find the server:
#!/bin/sh -eo pipefail
docker-compose run client psql -h server -p 5432 -U postgres -c "\l"
Starting project_server_1 ...
^#^#psql: could not connect to server: Connection refused
Is the server running on host "server" (172.18.0.2) and accepting
TCP/IP connections on port 5432?
Exited with code 2
Files
The docker-compose.yml looks like this
version: '2'
services:
server:
image: postgres:9.5.12-alpine
networks:
- internal
expose:
- '5432'
client:
build:
context: .
networks:
- internal
depends_on:
- server
networks:
internal:
driver: bridge
where the client is built from a dockerfile like this
FROM alpine:3.7
RUN apk --no-cache add postgresql-client && rm -rf /var/cache/apk/*
Note
If I repeat everything on my Linux (also with docker-in-docker) it works.
But I guess some things work completely different on circleci.
I found some people mentioning that on circleci networking and bind mounts can be tricky but I didn't find anything that can help me.
There is this doc but I thought I am doing this already.
Then there is this project where someone seems to do the same thing on circleci successfully.
But I cannot figure out what's different there...
Anyway I would really appreciate your help. So far I have given up on this.
Best
Marc
Ok, in the meanwhile I (no actually it was halfer from the circleci forum) noticed that docker-compose run client psql -h server -p 5432 -U postgres -c "\l" was run before the server was up and running. A simple sleep 5 after docker-compose up -d fixes the problem.

Openshift online zookeeper from dockerfile pod "Crash loop back off"

I want to deploy application on Openshift-origin online (next gen). There will be at least 4 pods communicating via services.
In 1st POD I have to run Zookeeper. So I created POD where my Zookeeper from docker image will be running, but POD's status is: Crash loop back off.
I created new project
oc new-project my-project
I created new app to deploy my zookeeper from docker
oc new-app mciz/zookeeper-docker-infispector --name zookeeper
And the output message was:
--> Found Docker image 51220f2 (11 minutes old) from Docker Hub for "mciz/zookeeper-docker-infispector"
* An image stream will be created as "zookeeper:latest" that will track this image
* This image will be deployed in deployment config "zookeeper"
* Ports 2181/tcp, 2888/tcp, 3888/tcp will be load balanced by service "zookeeper"
* Other containers can access this service through the hostname "zookeeper"
* This image declares volumes and will default to use non-persistent, host-local storage.
You can add persistent volumes later by running 'volume dc/zookeeper --add ...'
* WARNING: Image "mciz/zookeeper-docker-infispector" runs as the 'root' user which may not be permitted by your cluster administrator
--> Creating resources with label app=zookeeper ...
imagestream "zookeeper" created
deploymentconfig "zookeeper" created
service "zookeeper" created
--> Success
Run 'oc status' to view your app.
Then I ran pods list:
oc get pods
with output:
NAME READY STATUS RESTART AGE
zookeeper-1-mrgn1 0/1 CrashLoopBackOff 5 5m
Then I ran logs:
oc logs -p zookeeper-1-mrgn1
with output:
JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
grep: /opt/zookeeper/bin/../conf/zoo.cfg: No such file or directory
mkdir: can't create directory '': No such file or directory
log4j:WARN No appenders could be found for logger (org.apache.zookeeper.server.quorum.QuorumPeerConfig).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Invalid config, exiting abnormally
My dockerfile:
FROM openjdk:8-jre-alpine
MAINTAINER mciz
ARG MIRROR=http://apache.mirrors.pair.com
ARG VERSION=3.4.6
LABEL name="zookeeper" version=$VERSION
RUN apk add --no-cache wget bash \
&& mkdir /opt \
&& wget -q -O - $MIRROR/zookeeper/zookeeper-$VERSION/zookeeper- $VERSION.tar.gz | tar -xzf - -C /opt \
&& mv /opt/zookeeper-$VERSION /opt/zookeeper \
&& cp /opt/zookeeper/conf/zoo_sample.cfg /opt/zookeeper/conf/zoo.cfg
EXPOSE 2181 2888 3888
WORKDIR /opt/zookeeper
VOLUME ["/opt/zookeeper/conf"]
ENTRYPOINT ["/opt/zookeeper/bin/zkServer.sh"]
CMD ["start-foreground"]
There is a warning in the new-app command output:
WARNING: Image "mciz/zookeeper-docker-infispector" runs as the 'root' user which may not be permitted by your cluster administrator
You should fix the docker image to not run as root (or tell OpenShift to allow this project containers to run as root).
There is an specific example of Zookeeper image and template that works in Openshift.
https://github.com/openshift/origin/tree/master/examples/zookeeper
Notice the Dockerfile changes to run the container as non root user