Portainer - how to specify SSL in docker-compose.yml? - docker

I'm trying to deploy an instance of Portainer to a docker swarm. I'm not sure how to set the correct flag to enable SSL.
From the docs:
$ docker run -d -p 443:9000 --name portainer --restart always -v ~/local-certs:/certs -v portainer_data:/data portainer/portainer --ssl --sslcert /certs/portainer.crt --sslkey /certs/portainer.key
https://portainer.readthedocs.io/en/stable/deployment.html
But how do you translate that into a docker compose yml file?

Possibly I'm a bit late to the party, but it looks what you have to use Portainer's flags to enable ssl for your Portainer (as said in documentation) and composerize.com lost that part somewhere, so you should add this to your compose:
command:
--sslcert /certs/portainer.crt
--sslkey /certs/portainer.key
or for full compose file:
version: 3
services:
portainer:
image: portainer/portainer
container_name: portainer
restart: always
ports:
- '443:9000'
volumes:
- '~/local-certs:/certs'
- 'portainer_data:/data'
command:
--sslcert /certs/portainer.crt
--sslkey /certs/portainer.key

According to Portainer documentation:
By default, Portainer’s web interface and API is exposed over HTTP.
This is not secured, it’s recommended to enable SSL in a production
environment.
To do so, you can use the following flags --ssl, --sslcert and
--sslkey:
$ docker run -d -p 443:9000 --name portainer --restart always -v
~/local-certs:/certs -v portainer_data:/data portainer/portainer --ssl
--sslcert /certs/portainer.crt --sslkey /certs/portainer.key
You can use the following commands to generate the required files:
$ openssl genrsa -out portainer.key 2048
$ openssl ecparam -genkey -name secp384r1 -out portainer.key
$ openssl req -new -x509 -sha256 -key portainer.key -out portainer.crt -days 3650
Note that Certbot could be used as well to generate a certificate and a key.
As Rubin suggests, you can use https://composerize.com/ to generate a docker-compose.yml from docker command.
So, your docker-compose file should be something like this:
version: '3'
services:
portainer:
image: portainer/portainer
container_name: portainer
restart: always
ports:
- '443:9000'
volumes:
- '~/local-certs:/certs'
- 'portainer_data:/data'
command:
--ssl
--sslcert /certs/portainer.crt
--sslkey /certs/portainer.key
volumes:
portainer_data:

https://composerize.com/ can help to translate your docker command into a docker-compose.yml

The following works for me:
version: '3'
services:
portainer:
image: portainer/portainer-ce
volumes:
- "/local-certs:/certs"
- "portainer_data:/data"
restart: always
ports:
- "9000:9000"
container_name: portainer
command:
- --ssl
- --sslcert
- /certs/wildcard.crt
- --sslkey
- /certs/wildcard.key

Related

CERTBOT can't find config file in docker container

Two months ago, I set up a website with SSL thanks to Let's Encrypt. The details of how I did it are now quite blurry.
The site is hosted inside several docker containers (nginx, PHP, MySQL). There is a certbot container which should perform the renewal of the SSL certificate. This container is launched once a week and aborts immediately.
I have checked the logs and found this error. My research were unsuccessful and I have no idea what file certbot is complaining about.
usage:
certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...
Certbot can obtain and install HTTPS/TLS/SSL certificates. By default,
it will attempt to use a webserver both for obtaining and installing the
certificate.
certbot: error: Unable to open config file: certonly -n --webroot --webroot-path=/var/lib/challenge --email contact#**********.com --agree-tos --no-eff-email -d www.**********.com --key-type ecdsa. Error: No such file or directory
Do you have any idea of the problem?
Thanks in advance,
EDIT:
The contents of /etc/letsencrypt are
accounts archive cli.ini csr keys live renewal renewal-hooks
Inside cli.ini, I have :
key-type = ecdsa
elliptic-curve = secp384r1
rsa-key-size = 4096
email = contact#attom.eu
authenticator = webroot
webroot-path = /var/lib/challenge
agree-tos = true
The docker-compose.yml contains :
version: '3'
services:
nginx:
build: ./nginx
container_name: nginx
restart: unless-stopped
depends_on:
- php
networks:
- app-network
volumes:
- {{ mounted_dir_app }}/public:/var/www/html:ro
- certbotdata:/etc/letsencrypt:ro
- challenge:/home/challenge
ports:
- "80:80"
- "443:443"
env_file:
- .env
- ".env.$ENV"
healthcheck:
test: curl -IsLk $$SITE_URL | head -n 1 | grep -q -e ^HTTP -e 200
start_period: 30s
interval: 10s
timeout: 3s
retries: 5
php:
#skip
mysql:
#skip
certbot:
depends_on:
nginx:
condition: service_healthy
build:
context: ./certbot
args:
- "ENV=$ENV"
container_name: certbot
env_file:
- .env
- ".env.$ENV"
volumes:
- certbotdata:/etc/letsencrypt
- challenge:/var/lib/challenge
networks:
app-network:
driver: bridge
volumes:
dbdata:
certbotdata:
challenge:
Edit:
The CERTBOT Dockerfile is
ARG ENV
FROM certbot/certbot as cert-prod
CMD certonly -n --webroot --webroot-path=/var/lib/challenge --email contact#**********.com --agree-tos --no-eff-email -d www.**********.com --key-type ecdsa
FROM alpine as cert-dev
RUN apk update && apk add openssl
CMD mkdir -p /etc/letsencrypt/live/www.**********.com && \
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-subj "/C=**/ST=**********/L=**********" \
-keyout /etc/letsencrypt/live/www.**********.com/privkey.pem -out /etc/letsencrypt/live/www.**********.com/fullchain.pem
FROM cert-${ENV}

What is the difference between docker run --config vs docker compose config?

So what I am looking at is a docker run command being used in to create a docker container for open telemetry that passes in a config command, and the code looks like...
$ git clone git#github.com:open-telemetry/opentelemetry-collector.git; \
cd opentelemetry-collector/examples; \
go build main.go; ./main & pid1="$!";
docker run --rm -p 13133:13133 -p 14250:14250 -p 14268:14268 \
-p 55678-55679:55678-55679 -p 4317:4317 -p 8888:8888 -p 9411:9411 \
-v "${PWD}/local/otel-config.yaml":/otel-local-config.yaml \
--name otelcol otel/opentelemetry-collector \
--config otel-local-config.yaml; \
kill $pid1; docker stop otelcol
(https://opentelemetry.io/docs/collector/getting-started/#docker)
What I don't understand is how a non-docker related config file(open telemetry config) fits into the "docker run --config" or "docker compose config" commands. Below is the open telemetry config file that seems to be non-docker related
extensions:
memory_ballast:
size_mib: 512
zpages:
endpoint: 0.0.0.0:55679
receivers:
otlp:
protocols:
grpc:
http:
processors:
batch:
memory_limiter:
# 75% of maximum memory up to 4G
limit_mib: 1536
# 25% of limit up to 2G
spike_limit_mib: 512
check_interval: 5s
exporters:
logging:
logLevel: debug
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [logging]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [logging]
extensions: [memory_ballast, zpages]
https://github.com/open-telemetry/opentelemetry-collector/blob/main/examples/local/otel-config.yaml
Now I have looked at these Docker links
https://docs.docker.com/engine/swarm/configs/#how-docker-manages-configs
https://nickjanetakis.com/blog/docker-tip-43-using-the-docker-compose-config-command
but I couldn't figure out how to get the docker run --config command in the open telemetry example to start working in docker compose with docker compose config. Here is my docker compose
version: "3.9"
services:
opentelemetry:
container_name: otel
image: otel/opentelemetry-collector:latest
volumes:
- ~/source/repos/CritterTrackerProject/DockerServices/OpenTelemetry/otel-collector-config.yml:/otel-local-config.yml
config:
- otel-local-config.yml
ports:
- 13133:13133
- 14250:14250
- 14268:14268
- 55678-55679:55678-55679
- 4317:4317
- 8888:8888
- 9411:9411
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
- my-network
jaeger:
# restart: unless-stopped
container_name: jaeger
image: jaegertracing/all-in-one:latest
ports:
- 16686:16686
# - 14250:14250
# - 14268:14268
# - 5775:5775/udp
- 6831:6831/udp
# - 6832:6832/udp
# - 5778:5778
# - 9411:9411
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
- my-network
postgres:
restart: always
container_name: postgres
image: postgres:latest
environment:
- POSTGRES_USER=code
- POSTGRES_PASSWORD=code
ports:
- 5432:5432
volumes:
- postgres:/var/lib/postgresql/data
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
- my-network
nginx:
restart: always
container_name: webserver
image: nginx:latest
build:
context: ~/source/repos/CritterTrackerProject
dockerfile: DockerServices/Nginx/Dockerfile
ports:
- 80:80
- 443:443
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
- my-network
volumes:
postgres:
networks:
my-network:
external: true
name: my-network
Here is my error after running docker compose up in a Git Bash terminal
$ docker compose -f ./DockerServices/docker-compose.yml up -d
services.opentelemetry Additional property config is not allowed
The general form of docker run is
docker run [docker options] image [command]
And if you look at your original command it matches this pattern
docker run \
--rm -p ... -v ... --name ... \ # Docker options
otel/opentelemetry-collector \ # Image
--config otel-local-config.yaml # Command
So what looks like a --config option is really the command part of the container setup; it overrides the Dockerfile CMD, and it is passed as additional arguments to the image's ENTRYPOINT.
In a Compose setup, then, this would be the container's command:.
services:
opentelemetry:
image: otel/opentelemetry-collector:latest
command: --config otel-local-config.yaml
Since this is an application-specific command string, it's unrelated to the docker-compose config command, which is a diagnostic tool that just dumps out parts of your Compose configuration.
What you're doing in the docker run command is the following mounting:
${PWD}/local/otel-config.yaml on the local host to /otel-local-config.yaml from inside the docker
You can achieve same behavior with volumes option from docker compose:
volumes:
"${PWD}/local/otel-config.yaml":/otel-local-config.yaml

Install local portainer with docker compose

I'm reading the docker-ce dock for installation. It's simple two lines :
docker volume create portainer_data &&
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
Is there a way to do all this stuff with docker-compose file ? So the portainer container will be groupped with all the others when executing docker-comppose down ?
This french tutorial got something working :
portainer:
container_name: portainer
image: portainer/portainer-ce:latest #latest might not be the best option
restart: unless-stopped
command: -H unix:///var/run/docker.sock
ports:
- 9000:9000
volumes:
- /var/run/docker.sock:/var/run/docker.sock:fr
- /etc/localtime:/etc/localtime:fr
- /etc/timezone:/etc/timezone:fr #not sure about those 3 volumes
- dataportainer:/data
volumes:
dataportainer:

Traefik cannot reach backend when docker-compose has port mapping

My docker is in swarm mode.
I am puzzled about why traefik is no more able to reach my nexus backend as soon as I settle a port mapping from within its compose file : I got a 504 (timeout) error instead. Without the mapping, traefils works fine.
Traefik is deployed on the swarm, as a service, with the following command :
docker network create --driver=overlay traefik-net
docker service create \
--name traefik \
--constraint=node.role==manager \
--publish 80:80 --publish 8088:8080 \
--with-registry-auth \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
--mount type=bind,source=/var/opt/data/flat/gerdce/shared/servers/traefik/out/,target=/out/ \
--mount type=bind,source=/var/opt/data/flat/gerdce/shared/servers/traefik/traefik.toml,target=/traefik.toml \
--network traefik-net \
dvckzasc03.rouen.francetelecom.fr:5000/pli/traefik \
--docker \
--docker.domain=docker.localhost \
--docker.swarmMode=true \
--docker.watch=true \
--api
(Il also tried running traefik from a docker-compose file, but with no more success)
The nexxus stack :
version: '3.3'
services:
nexus:
image: some_nexus:5000/sonatype/nexus3
volumes:
- /var/opt/data/flat/gerdce/shared/repositories/nexus/data:/nexus-data
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
labels:
- "traefik.enable=true"
- "traefik.static.frontend.rule=PathPrefix:/static/rapture"
- "traefik.serviceext.frontend.rule=PathPrefix:/service/extdirect"
- "traefik.serviceout.frontend.rule=PathPrefix:/service/outreach"
- "traefik.nexus.frontend.rule=PathPrefixStrip:/nexus"
- "traefik.port=8081"
networks:
- traefik-net
#ports:
#- "5050:5050"
networks:
traefik-net:
external: true
Everything works fine this way : traefik redirects well every call to /nexus (and s.o.) .... until I uncomment the port mapping!
I really need this port mapping, in order to login / push / pull from my VM.
Any idea on
why this is happening (have I missed stg from the docs ?
what may be the fix or workaround here?
Versions :
Docker version 18.03.0-ce, build 0520e24
docker-compose version 1.22.0, build f46880fe
Traefik 1.6.5
First, I would recommend sticking this into a docker-stack.yml like your Nexus stack file as it will be easier to maintain.
Here's an example of a traefik proxy I deployed yesterday which works with port mappings
version: "3.4"
services:
traefik:
image: traefik:latest
ports:
- "80:80"
- "443:443"
- "8080:8080"
Eventually, I had it working adding a missing label:
- "traefik.docker.network=traefik-net"

How to dockerize a third-party go application

Alongside the Docker containers running my micro-services written in go (one container per micro-service), I need to create a Docker container that runs the Service Registry service provided by a third-party framework (Koding's kontrol).
Having said that, I need to create a separate container that runs this third-party go application by executing the following commands.
Retrieve the application:
go get github.com/koding/kite/kontrol/kontrol
Generate RSA key pair:
openssl genrsa -out key.pem 2048
openssl rsa -in key.pem -pubout > key_pub.pem
Set some environment variables:
KONTROL_PORT=6000
KONTROL_USERNAME="kontrol"
KONTROL_STORAGE="etcd"
KONTROL_KONTROLURL="http://127.0.0.1:6000/kite"
KONTROL_PUBLICKEYFILE="certs/key_pub.pem"
KONTROL_PRIVATEKEYFILE="certs/key.pem"
Initialize the Registry Service:
./bin/kontrol -initial
Start the Registry Service:
./bin/kontrol
How do I include these steps in my project? For instance, I have a docker-composer.yaml file like this:
version: '3.3'
services:
api:
container_name: 'api'
build: './api'
ports:
- '8080:8080'
volumes:
- './api:/go/src/app'
depends_on:
- 'mongo'
etcd0:
container_name: 'etcd0'
image: 'quay.io/coreos/etcd'
command: >
etcd -name etcd0
-advertise-client-urls http://127.0.0.1:2379,http://127.0.0.1:4001
-listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001
-initial-advertise-peer-urls http://127.0.0.1:2380
-listen-peer-urls http://0.0.0.0:2380
-initial-cluster-token etcd-cluster-1
-initial-cluster etcd0=http://127.0.0.1:2380
-initial-cluster-state new
mongo:
container_name: 'mongo'
image: 'mongo:latest'
ports:
- '27017:27017'
volumes:
- '/var/lib/mongodb:/var/lib/mongodb'

Resources