Dlaczego Docker? Wiele osób pyta mnie, czy do nauki potrzebne jest specjalne środowisko lub klaster. Klaster na pewno jest fajną opcją. Mimo wszystko sporo możliwości daje pojedyncza maszyna z Dockerem na pokładzie.
Dlaczego Docker?
Od momentu gdy poznałem podstawy Docker, nie potrafię sobie przypomnieć kiedy instalowałem jakąś bazę danych na swoim komputerze. Bardzo ułatwia pracę, deweloperkę i poznawanie nowych technologii bez zaśmiecania sobie systemu. Nie będę wchodzić w szczegóły opisując co to jest i jak to działa. W skrócie: jest to lekka wirtualizacja. Aplikacje opakowane są w kontenery, przez co w łatwy i powtarzalny sposób można je przenosić i odpalać na różnych maszynach. Możemy zasymulować klaster uruchamiając kilka kontenerów naraz.
Warto zastanowić się nad skonteneryzowaniem swojej aplikacji. Na końcu wpisu znajdziesz przykład konteneryzacji aplikacji w Pythonie z biblioteką Flask
Co warto wiedzieć?
Docker Compose
Zamiast pisać za każdym razem “docker run … <milion opcji> … <nazwa kontenera>”, można spisać to w formie plku YAML i uruchamiać nawet kilka kontenerów naraz. Kontenery mogą być od siebie zależne (np. aplikacja jest zależna od bazy danych, więc ta powstanie pierwsza)
Porty
Jeśli chcesz dostać się do usług jakiegoś kontenera pamiętaj o wystawieniu odpowiedniego portu
Volume
Volume to zmapowanie systemu plików w kontenerze do systemu plików systemu operacyjnego maszyny. Jeśli postawisz kontener z bazą i nie zmapujesz odpowiedniego folderu, po wyłączeniu kontenera prawdopodobnie stracisz dane.
Network
Jeśli zależy Ci na tym, aby kilka kontenerów ze sobą gadało, upewnij się, że są w tej samej sieci (dockerowej)
DNS
Docker ma swojego wewnętrznego dns-a dla utworzonych sieci, więc jeśli utworzysz kontener o nazwie XYZ, to po tej właśnie nazwie znajdą go inne kontenery w tej samej sieci.
Kilka komend
- docker exec -it <nazwa kontenera> /bin/bash lub jesli kontener nei ma bash-a docker exec -it <nazwa kontenera> sh – odpalenie terminala z poziomu konteneru
- docker logs <nazwa kontenera> – wyświetlenie logów danego kontenera. Jeśli chcesz śledzić je na bierząco wystarczy dodać -f
Lista kontenerów
Poniżej zebrałem kilka aplikacji/systemów/jak zwał które mają na celu zainteresować Cię tematem. Może akurat zastanawiasz się jak na szybko coś odpalić. Koniecznie zerknij na Docker Hub, zanim zaczniesz coś instalować na swojej maszynie deweloperskiej.
Jupyter
docker run -d -P --name notebook jupyter/all-spark-notebook
Szczegóły znajdziesz w dokumentacji. Jeśli interesuje Cię PySpark, Apache Spark i Scala, warto zerknąć tutaj
Apache Airflow
Tej techonologii użyłem w mini projekcie związanym z danymi GPS komunikacji miejskiej w Warszawie. Postawienie go ręcznie pip-em wymaga spełnienia pewnych zależności. W przypadku dockera problem ten nas nie dotyczy. Warto zerknąć na repozytorium https://github.com/puckel/docker-airflow. Poniżej Docker Compose z tego repo.
version: '2.1'
services:
postgres:
image: postgres:9.6
environment:
- POSTGRES_USER=airflow
- POSTGRES_PASSWORD=airflow
- POSTGRES_DB=airflow
webserver:
image: puckel/docker-airflow:1.10.6
restart: always
depends_on:
- postgres
environment:
- LOAD_EX=n
- EXECUTOR=Local
volumes:
- ./dags:/usr/local/airflow/dags
# Uncomment to include custom plugins
# - ./plugins:/usr/local/airflow/plugins
ports:
- "8080:8080"
command: webserver
healthcheck:
test: ["CMD-SHELL", "[ -f /usr/local/airflow/airflow-webserver.pid ]"]
interval: 30s
timeout: 30s
retries: 3
Microsoft SQL Server
Zdziwiony? MSSQL można odpalić na linuchu i to w formie dockera. Poniższa komenda odpali nam SQL Server w wersji 2017 Express.
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=yourStrong(!)Password' -e 'MSSQL_PID=Express' -p 1433:1433 -d mcr.microsoft.com/mssql/server:2017-latest-ubuntu
Apache Kafka
W internecie znajdziesz kilka sposobów/obrazów/kontenerów z Apache Kafka. Pisał też o tym Radek na http://bigdatapassion.pl/blog/kafka/kafka-docker/ . Ja używam poniższego Docker Compose opartego o kontener utworzony przez firmę Bitnami.
version: '2'
services:
zookeeper:
image: 'bitnami/zookeeper:3'
ports:
- '2181:2181'
volumes:
- 'zookeeper_data:/bitnami'
environment:
- ALLOW_ANONYMOUS_LOGIN=yes
kafka:
image: 'bitnami/kafka:2'
ports:
- '9092:9092'
- '29092:29092'
volumes:
- 'kafka_data:/bitnami'
environment:
- KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
- ALLOW_PLAINTEXT_LISTENER=yes
- KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,PLAINTEXT_HOST://:29092
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
- KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
depends_on:
- zookeeper
volumes:
zookeeper_data:
driver: local
kafka_data:
driver: local
Cassandra
Postawienie Cassandry to banał. Istnieje oficjalny kontener z prostą dokumentacją. Jest opcja postawienia klastra. Poniżej przykład włączenia konsoli cassandry w kontenerze.
maciej@ubuntu:~$ sudo docker exec -it some-cassandra cqlsh
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.1.21 | CQL spec 3.2.1 | Native protocol v3]
Use HELP for help.
cqlsh>
Elasticsearch + Kibana
Mój ulubiny zestaw do zbierania logów. Poniżej docker compose, którego najczęściej używam. Pamietaj o odpowiednim skonfigurowaniu linucha.
version: '2.2'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.1.1
restart: unless-stopped
environment:
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata:/usr/share/elasticsearch/data
ports:
- 9200:9200
networks:
- esnet
kibana:
image: docker.elastic.co/kibana/kibana:7.1.1
restart: unless-stopped
depends_on:
- elasticsearch
ports:
- 5601:5601
volumes:
- kibanadata:/usr/share/kibana/data
networks:
- esnet
volumes:
esdata:
driver: local
kibanadata:
driver: local
networks:
esnet:
Własny kontener
Poniżej przykład Dockerfile dla zestawu Python + Flask. Aplikacja jest to plik app.py, a hostowana jest gunicornem. W pliku requirements.txt znajdują się wszystkie potrzebne biblioteki do pobrania przez pip-a.
FROM python:3.8-alpine
RUN adduser -D someuser
WORKDIR /home/app
RUN apk add --no-cache --update python3-dev gcc build-base
COPY requirements.txt requirements.txt
RUN python -m venv venv
RUN apk add --no-cache --update python3
RUN python3 -m ensurepip
RUN venv/bin/pip3 install --upgrade pip
RUN venv/bin/pip3 install -r requirements.txt
RUN venv/bin/pip3 install gunicorn
COPY ./ .
RUN chmod +x /home/app/boot.sh
ENV FLASK_APP app.py
RUN chown -R bell:bell ./
USER someuser
EXPOSE 5000
ENTRYPOINT ["/home/app/boot.sh"]
Po wrzuceniu Dockerfile do katalogu z aplikacją wystarczy “docker build -t moj-kontenerek .” Kod Dockerfile jest dość prosty. Bierzemy kontener python-…, następnie instalowane są zależności, kopiowany kod aplikacji, wystawiany port 5000, a pod koniec ustawiany skrypt boot.sh jako Entrypoint. Treść pliku poniżej.
source venv/bin/activate
exec gunicorn -b :5000 --access-logfile - --error-logfile - app:app
Cześć,
Co do wystawiania własnego kontenera to… ten twój Dockerfile aż błaga o optymalizację 😉 zwłaszcza jak ładujesz początkowo jakieś kompilatory, to aż prosiło o użycie multi-stage build… (im lżejszy kontener, tym lepiej)
https://docs.docker.com/develop/develop-images/multistage-build/
Hej, pewnie masz racje. W tym przypadku (z tego co pamiętam) gcc bylo potrzebne do zainstalowania pipem gunicorna. Same kod aplikacji, z racji ze to python, sie nie kompiluje. Jak tworzę kontenery .net core to uzuwam multi-stage build.