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.