Cześć,
obserwując nowinki technologiczne można było zauważyć iż jakiś czas temu miał miejsce boom na oprogramowanie które nosiło nazwę Vagrant. Ogólnie chodziło o to że w łatwy sposób mogłeś stworzyć sobie maszynę wirtualną z wybranym przez siebie systemem, łatwo nią zarządzać, dbać o aktualizacje czy tworzyć prosty provisioning. Rozwój wirtualizacji pokazał jednak iż można zrobić to lżej – nie emulować całej maszyny a tylko jakby jej środowisko uruchomieniowe – czyli system. I w oparciu o taką ideę powstał Docker.
Docker jest lekkim środowiskiem wirtualizacyjnym, stworzonym z myślą o szybkim i prostym wdrażaniu oraz publikacji zmian. Kontenery dockerowe można uruchomić wszędzie tam gdzie udało się zainstalować Dockera i we wszystkich tych miejscach te kontenery będą działały tak samo.
Kontener – to, jak wcześniej wspomniałem – środowisko uruchomieniowe dla Twoich aplikacji. Mamy do wyboru wiele obrazów takich kontenerów, które w prosty sposób pozwalają na uruchomienie serwera HTTP, bazy danych czy czegokolwiek innego. Takie „prymitywne” obrazy najczęściej służą jako postawa do pisania własnych kontenerów.
Stworzymy dziś dwa kontenery w oparciu o mój poprzedni wpis – o własnej centrali telefonicznej – ponieważ jeśli go czytałeś – to pewnie zauważyłeś że sporo pracy musi wykonać czytelnik aby uruchomić centralę na swoim komputerze. Dzięki Dockerowi uprościmy to :)
Stwórzmy więc taką hierarchię folderów, gdzie rootem jest Twój katalog domowy:
- ~/ - docker - docker_asterisk - docker_postgres
i przejdźmy do folderu docker_postgres w którym stworzymy kontener postgresa w wersji 9.2.
Chcemy teraz aby nasz kontener z postgresem miał już stworzony schemat bazy danych, odpowiedniej dla Asteriska – w spisie poprzednim korzystaliśmy z gotowej migracji i aplikacji alembic – tutaj zrobimy to samo, więc na początek dostarczmy do tego folderu plik config.ini:
# A generic, single database configuration. [alembic] # path to migration scripts script_location = config # template used to generate migration files # file_template = %%(rev)s_%%(slug)s # max length of characters to apply to the # "slug" field #truncate_slug_length = 40 # set to 'true' to run the environment during # the 'revision' command, regardless of autogenerate # revision_environment = false #sqlalchemy.url = driver://user:pass@localhost/dbname #sqlalchemy.url = postgresql://user:pass@localhost/asterisk #sqlalchemy.url = mysql://user:pass@localhost/asterisk sqlalchemy.url = postgresql://matt:test@localhost/asterisk [logger_root] level = WARN handlers = console qualname = [logger_sqlalchemy] level = WARN handlers = qualname = sqlalchemy.engine [logger_alembic] level = INFO handlers = qualname = alembic [handler_console] class = StreamHandler args = (sys.stderr,) level = NOTSET formatter = generic [formatter_generic] format = %(levelname)-5.5s [%(name)s] %(message)s datefmt = %H:%M:%S
poza tym będziemy potrzebować skryptów które zmienią nam plik pg_hba.conf oraz utworzą odpowiednich użytkowników. Zacznijmy od tego pierwszego i nazwijmy go setupConnection.sh:
sed -i '/host all all 127.0.0.1\/32 trust/a host all all 172.17.0.1\/16 md5' /var/lib/postgresql/data/pg_hba.conf
No i drugi o nazwie setup.sh:
psql -U postgres -c "CREATE USER matt WITH PASSWORD 'test';" psql -U postgres -c "CREATE DATABASE asterisk;" psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE asterisk TO matt;" cd ../asterisk-13.13.1/contrib/ast-db-manage/ alembic -c config.ini upgrade head
Aby stworzyć kontener potrzebny jest przepis jak zbudować obraz z którego później będzie można tworzyć nieograniczoną liczbę kontenerów. Przepis ten umieszczamy w pliku Dockerfile i dla naszego postgresa będzie on wyglądać tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | FROM postgres:9.2 ADD setupConnection.sh /docker-entrypoint-initdb.d/setupConnection.sh RUN chmod 755 /docker-entrypoint-initdb.d/setupConnection.sh ADD setup.sh /docker-entrypoint-initdb.d/setup.sh RUN chmod 755 /docker-entrypoint-initdb.d/setup.sh RUN apt-get update -y && apt-get install -y wget && apt-get install -y postgresql-server-dev-9.2 build-essential autoconf libtool pkg-config python-opengl python-imaging python-pyrex python-pyside.qtopengl idle-python2.7 qt4-dev-tools qt4-designer libgle3 python-dev RUN wget https://bootstrap.pypa.io/get-pip.py && python get-pip.py RUN pip install psycopg2 alembic RUN wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-13-current.tar.gz RUN tar -zxvf asterisk-13-current.tar.gz ADD config.ini / RUN cp /config.ini asterisk-13.13.1/contrib/ast-db-manage/ |
A więc o tu się dzieje… Słówko „FROM” określa z jakiego kontenera wychodzimy – tzn który rozszerzamy. Wychodzimy więc z kontenera „postgres:9.2”. Dalej poleceniem ADD kopiujemy stworzone wcześniej pliki do folderu „docker-entrypoint-initdb.d” który już znajduje się w kontenerze – był stworzony w obrazie „postgres:9.2” i jego „entrypoint” definiuje się jako „uruchom wszystkie pliki sh z folderu docker-entrypoint-initdb.d” – więc w sumie dokładnie o to nam chodzi. Entrypoint to polecenia które wykonują sie za każdym razem jak kontener startuje. Poleceniem RUN – nadajemy plikom możliwość ich wykonania. Następnie polecenie już mocno customizuje nasz kontener – instalujemy wszystkie zależności do pythona, po cztym instalujemy pipa, potem alembic’a, ściągamy asteriska, wypakowujemy go i kończąc – przenosimy nasz config.ini do folderu z migracjami. I to tyle. Aby uruchomić nasz kontener pierw musimy zbudować jego obraz, robimy to tak, będąc w folderze z Dockerfile’em postgresa:
1 | docker build -t postgres92 . |
i widzimy:
Sending build context to Docker daemon 6.144 kB Step 1 : FROM postgres:9.2 ---> 02b45836f2c8 Step 2 : ADD setupConnection.sh /docker-entrypoint-initdb.d/setupConnection.sh ---> 15ba58b40cca Removing intermediate container 9b61056d6cae Step 3 : RUN chmod 755 /docker-entrypoint-initdb.d/setupConnection.sh ---> Running in f6d0d81f634c ---> 39e76a1b1754 Removing intermediate container f6d0d81f634c Step 4 : RUN apt-get update -y && apt-get install -y wget && apt-get install -y postgresql-server-dev-9.2 build-essential autoconf libtool pkg-config python-opengl python-imaging python-pyrex python-pyside.qtopengl idle-python2.7 qt4-dev-tools qt4-designer libgle3 python-dev ---> Running in 8cce9e8fa323 ....
On wykona wszystkie nasze polecenia, czego wynikiem będzie obraz kontenera o nazwie postgres92.
Uruchommy ten kontener:
docker run -d --name postgres92 postgres92
Wykonaniem tej komendy uruchomiliśmy kontener o nazwie postgres92 na podstawie obrazu o nazwie postgres92. Zalogujmy się do psql’a:
docker exec -it postgres92 psql -U matt -d asterisk
Komenda docker exec -it nazwa_kontenera pozwala na uruchomienie binarki na tym kontenerze. A więc wykonanie tego polecenia skutkuje zalogowanie się do bazy danych:
psql (9.2.19) Type "help" for help. asterisk=>
Więc działa :) Skoro mamy już Postgresa, to czas na Asteriska.
Aby Asterisk podziałał potrzebne są nam pliki konfiguracyjne – spakujmy się do pliki config.tar.gz i przenieśmy do folder docker_asterisk. Dla leniwych plik do ściągnięcia – w formacie zip – należy go przepakować do formatu tar.gz – wybaczcie, ale mój WordPress mocno nie pozwalał bym wrzucał tar.gz’ta do wpisu. No i standardowo jak w przypadku Postgresa, Dockerfile:
1 2 3 4 5 6 7 8 9 10 11 | FROM centos:7 RUN yum upgrade -y && yum install -y epel-release dmidecode gcc-c++ ncurses-devel libxml2-devel make wget openssl-devel newt-devel kernel-devel sqlite-devel libuuid-devel gtk2-devel jansson-devel binutils-devel && yum -y install patch postgresql-devel postgresql-contrib bzip2 RUN wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-13-current.tar.gz && tar -zxvf asterisk-13-current.tar.gz && cd asterisk-13.13.1/ WORKDIR asterisk-13.13.1/ RUN ./configure --with-pjproject-bundled && make && make install && make samples WORKDIR / ADD config.tar.gz /config.tar.gz RUN rm -rf /etc/asterisk/* && cp config.tar.gz/* /etc/asterisk/ RUN echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local.conf && /sbin/ldconfig CMD asterisk -vvvvf |
W tym przypadku wychodzimy z Centosa 7ego. Nie ma tu nic bardzo odkrywczego – instalujemy zależności, ściągamy Asteriska, rozpakowujemy, kompilujemy, instalujemy, przenosimy nasz config.tar.gz (nie musimy go rozpakować – Docker zrobi to za nas), nadpisujemy standardowy config Asteriska, dodajemy ścieżkę do bibliotek dzielonych i uruchamiany Asteriska :) I standardowo go budujemy:
1 | docker build -t asterisk13 . |
co, również standardowo uruchamia proces budowania obrazu:
Sending build context to Docker daemon 1.927 MB Step 1 : FROM centos:7 ---> 67591570dd29 Step 2 : RUN yum upgrade -y && yum install -y epel-release dmidecode gcc-c++ ncurses-devel libxml2-devel make wget openssl-devel newt-devel kernel-devel sqlite-devel libuuid-devel gtk2-devel jansson-devel binutils-devel && yum -y install patch postgresql-devel postgresql-contrib bzip2 ---> Using cache ---> 598cd0b19227 Step 3 : RUN wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-13-current.tar.gz && tar -zxvf asterisk-13-current.tar.gz && cd asterisk-13.13.1/ ---> Using cache ---> 23780a537960 Step 4 : WORKDIR asterisk-13.13.1/ ---> Using cache ---> df51f92b998e Step 5 : RUN ./configure --with-pjproject-bundled && make && make install && make samples ---> Using cache ---> d1ff27432767 Step 6 : WORKDIR / ---> Using cache ---> f41fd90a3902 ...
W moim przykładzie Docker skorzystał z cache’a (kawałek „Using cache”) – gdyż nim ten wpis powstał wielokrotnie budowałem ten obraz. Uruchamiany kontener:
docker run -d --name asterisk13 asterisk13i przejść do konsoli Asteriska:
docker exec -it asterisk13 asterisk -r
Co daje poprawny rezultat:
1 2 3 4 5 6 7 8 9 10 | Connected to Asterisk 13.13.1 currently running on 3dcd15318ef0 (pid = 1) [Feb 5 12:26:38] ERROR[99]: res_config_pgsql.c:167 _pgsql_exec: PostgreSQL RealTime: Failed to query 'ps_contacts@asterisk'. [Feb 5 12:26:38] ERROR[99]: res_config_pgsql.c:168 _pgsql_exec: PostgreSQL RealTime: Query Failed: SELECT * FROM ps_contacts WHERE expiration_time <= '1486297598' ORDER BY expiration_time [Feb 5 12:26:38] ERROR[99]: res_config_pgsql.c:169 _pgsql_exec: PostgreSQL RealTime: Query Failed because: (PGRES_FATAL_ERROR) [Feb 5 12:26:38] ERROR[99]: res_config_pgsql.c:1540 pgsql_reconnect: PostgreSQL RealTime: Failed to connect database asterisk on 127.0.0.1: [Feb 5 12:26:38] NOTICE[99]: res_config_pgsql.c:153 _pgsql_exec: reconnect failed 3dcd15318ef0*CLI> |
Jak widzimy nasz Asterisk rzuca błędami – nie może połączyć się z postgresem – no i ma rację. Aby kontenery mogły się widzieć można je zlinkować, połączyć w sieć lub po prostu przybindować do maszyny lokalnej. My użyjemy ostatniej możliwości. Aby to osiągnąć skorzystamy z docker compose’a – czyli oprogramowania które pozwala grupować, łączyć i zarządzać wieloma kontenerami naraz (sudo dnf install docker-compose).
A więc w folderze wyżej, tj w folderze docker stwórzmy plik docker-compose.yml z zawartością:
1 2 3 4 5 6 7 8 9 10 11 12 | version: '2' services: postgres92: container_name: postgres92 build: docker_postgres/ network_mode: "host" asterisk13: container_name: asterisk13 build: docker_asterisk/ network_mode: "host" depends_on: - postgres92 |
Gdzie deklarujemy że używamy wersji drugiej pliku compose’a i chcemy stworzyć dwie usługi, jedną na bazie obrazu postgres92 i nazwie postgres92, gdzie plik Dockerfile znajduje się w folderze docker_postgres i typie sieci – „host” – które pozwala korzystać ze stworzonych usług tak jakby były uruchomione na komputerze (rozwiązuje problemy z przekierowywaniem portów itp).
Druga usługa to nasz Asterisk i jego definicja nie różni się niczym od definicji postgres’a poza elementem „depends_on” które definiuje kolejność podnoszonych kontenerów – więc jeśli kontener asterisk13 zależy od kontenera postgres92 to Docker uruchomi postgresa jako pierwszego – co ma sens, bo jeśli byłoby inaczej – Asterisk próbowałby się połączyć do jeszcze nie uruchomionej bazy danych.
A więc zabijamy wcześniej utworzone kontenery:
docker rm postgres92 asterisk13 -f
i w folderze z utworzonym plikiem docker-compose.yml uruchamiany:
docker-compose up
Co powoduje podniesienie Asteriska jak i postgresa, zrzut z mojego Terminatora:
Na górze działający compose, na dole po prawej połączenie z postgresem a na dole po lewej Asterisk :)
Aby móc dzwonić nalezy wykonać te SQLki co w poprzednim poście:
insert into ps_aors (id, max_contacts) values (22444444, 1); insert into ps_aors (id, max_contacts) values (22555555, 1); insert into ps_auths (id, auth_type, password, username) values (22444444, 'userpass', 1, 22444444); insert into ps_auths (id, auth_type, password, username) values (22555555, 'userpass', 2, 22555555); insert into ps_endpoints (id, transport, aors, auth, context, disallow, allow, direct_media) values (22444444, 'transport-udp', '22444444', '22444444', 'testing', 'all', 'ulaw,alaw', 'no'); insert into ps_endpoints (id, transport, aors, auth, context, disallow, allow, direct_media) values (22555555, 'transport-udp', '22555555', '22555555', 'testing', 'all', 'ulaw,alaw', 'no');
Ale tym razem bez UPDATE’a o którym wspomniałem tam, gdyż teraz nie mamy NATu. W zamian należy wykonać:
update ps_endpoints set rewrite_contact='yes';
i przeładować asteriska. Co powoduje że możemy do siebie dzwonić
No i w sumie to tyle :) Docker ma potencjał, mimo iż raczej nie jest używany na produkcjach.
Kilka rzeczy o których nie było po drodze mi wspomnieć:
1. Kontenery są domyślnie bezstanowe. Co w przypadku Asteriska jest znośne, to w przypadku postgresa średnio – fajnie by było jednak między wyłączeniem a włączeniem komputera tę samą zawartość bazy. Jest to zrealizowane w obrazie Postgresa poleceniem VOLUME:
VOLUME /var/lib/postgresql/data
które montuje wskazany katalog na hoście.
2. Mimo dodania „depends_on” Asterisk i tak czasem ma problem z połączeniem z bazą przez chwilkę. Wynika to stąd że Docker nie czeka aż usługi nam się podniosą a jedynie je startuje – to jest trochę race condition – czasem Asterisk wstanie później nim baza zacznie przyjmować zapytania a czasem wcześniej. Poprawić to można poprzez skrypt „wait-for-it.sh” – https://github.com/vishnubob/wait-for-it – czyli dodać go poleceniem ADD do Dockerfile’a Asteriska i poleceniem CMD zmienić na
CMD ["./wait-for-it.sh", "localhost:5432", "--", "asterisk -vvvvf"]
Co wymusi poczekanie ze wystartowaniem Asteriska nim baza wstanie.
3. Przydatne komendy..
docker exec -it asterisk13 bash
uruchamia na kontenerze basha – więc dzięki temu możemy sobie pochodzić po filesystemie – przydatne przy debuggowaniu.
docker rm postgres92 asterisk13 -f
usuwa kontenery. W tym przypadku są to dwa kontenery – postgres92 i asterisk13.
docker rmi postgres92 -f
usuwa obraz i kontenery stworzone za jego pomocą.
docker rm $(docker ps -a -q)
Usuwa wszystkie kontenery.
docker rmi $(docker images -q)
Usuwa wszystkie obrazy.
docker inspect asterisk13
Pokazuje informacje o kontenerze.
docker logs asterisk13
Pokazuje logi z kontenera.
docker-compose up --build
Wymusze rebuild kontenerów.
docker ps -a
Pokazuje kontenery.
Oj daaawnoo mnie tu nie było. Ale wakacje to był czas dużej liczby intensywnych wyjazdów i tak naprawdę, dopiero jakoś… Read More
Cześć! Zapraszam na krótkie podsumowanie kwietnia. Wyjazd do Niemiec A dokładniej pod granicę z Francją. Chrześnica miała pierwszą komunię. Po… Read More
Ostatnio tygodnie były tak bardzo wypełnione, że nie udało mi się napisać nawet krótkiego podsumowanie. Więc dziś zbiorczo podsumuję luty… Read More
Zapraszam na krótkie podsumowanie miesiąca. Książki W styczniu przeczytałem "Homo Deus: Historia jutra". Książka łudząco podoba do wcześniejszej książki tego… Read More
Cześć! Zapraszam na podsumowanie roku 2023. Książki Zacznijmy od książek. W tym roku cel 35 książek nie został osiągnięty. Niemniej… Read More
Zapraszam na krótkie podsumowanie miesiąca. Książki W grudniu skończyłem czytać Mein Kampf. Nudna książka. Ciekawsze fragmenty można by było streścić… Read More