12/08/2018, 00:23

Tìm hiểu về Docker (cont)

Trong bài viết trước chúng ta đã hiểu được Docker là gì, cách tạo image với câu lệnh và bằng Dockerfile cũng như sự giống và khác nhau giữa Docker và Vagrant. Trong bài viết này sẽ hướng dẫn về cách tạo image là một Ruby on Rails app và cách kết nối các image trong Docker với nhau. 1. Tạo Docker ...

Trong bài viết trước chúng ta đã hiểu được Docker là gì, cách tạo image với câu lệnh và bằng Dockerfile cũng như sự giống và khác nhau giữa Docker và Vagrant. Trong bài viết này sẽ hướng dẫn về cách tạo image là một Ruby on Rails app và cách kết nối các image trong Docker với nhau.

1. Tạo Docker Image

Tạo một Dockerfile như dưới đây trong folder của project để tạo Docker Image

FROM ruby:2.1.2

RUN bundle config --global frozen 1

RUN mkdir -p /usr/src/app

ADD . /usr/src/app/
WORKDIR /usr/src/app

RUN bundle install
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

Trong Dockerfile trên thì:

  • Base Image được sử dụng trong Dockerfile trên được pull về từ repo:
    https://registry.hub.docker.com/_/ruby/
    Repo trên có rất nhiều image của các version Ruby như 2.0.0, 2.1.1, 2.2.2,...Sử dụng phiên bản ruby nào tùy thuộc vào project của bạn.
  • Sau đó thì add workdir và chạy bundle install.

Chạy câu lệnh dưới đây để tạo image:
sudo docker build -t linuxhjkaru/test-app:v1 .
Sau khi câu lệnh chạy xong thì chúng ta đã có một docker image của Rails app

|REPOSITORY|TAG|IMAGE ID|CREATED|VIRTUAL SIZE |:---------|:------------|:------| | linuxhjkaru/test-app | v1 | 4484d1d8f49a |1 minute ago | 209.6 MB

2. Chạy server

Sau khi đã có image của Rails app thì chạy image với câu lệnh dưới đây
sudo docker run linuxhjkaru/test-app:v1

Image sẽ chạy với container như dưới đây:

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAME
8dc80b013746 linuxhjkaru/test-app:v1 "rails server -b 0.0" 2 minutes ago Up 2 minutes 3000/tcp furious_thompson

Như vậy là server Rails app của chúng ta đã chạy. Với rails app thì địa chỉ default sẽ là http://localhost:3000. Tuy nhiên vì được chạy trong container nên khi truy cập vào địa chỉ trên thì sẽ không kết nối đươc. Khi chạy Docker thì Docker sẽ lấy địa chỉ default là localhost:80, do đó để chạy được web trên cần chạy container bằng câu lệnh:
sudo docker run -p 80:3000 linuxhjkaru/test-app:v1

Câu lệnh trên sẽ map port 80 của Docker về port 3000 ở bên trong container. Truy cập địa chỉ : http://localhost:80 và sẽ thấy trang web của chúng ta hiện ra.
Hoặc có thể chỉ định địa chỉ nào đó như:
sudo docker run -p 127.0.0.1:4000:3000 linuxhjkaru/test-app:v1 Lúc này để truy cập vào web thì chúng ta dùng địa chỉ: 127.0.0.1:4000

Để chạy container background thì thêm vào flag -d.
Để restart server thì restart container bằng câu lệnh: sudo docker restart furious_thompson.
Để stop server thì sẽ dừng container bằng câu lệnh sudo docker stop furious_thompson.

3. Kết nối với Database

Để kết nối với Database thì trong file database.yml để địa chỉ của database là biến môi trường như sau

database: homeup_production
  hosts:
    - <%= ENV['MONGODB_HOST'] %>:27017

Chạy Image với câu lệnh sau:

sudo docker run --rm -e "MONGODB_HOST=127.0.0.1" linuxhjkaru/test-app:v1

Như vậy là web của chúng ta đã kết nối được với database. Tương tự như vậy có thể truyền vào các biến môi trường như RAILS_EN, database password...

sudo docker run --rm -e "RAILS_ENV=production" -e "MONGODB_HOST=127.0.0.1" linuxhjkaru/test-app:v1

Nếu như database cũng là một image và chạy bên trong một Docker Container thì cần phải link container chứa app với container chứa id.
Chạy image db bằng câu lệnh:
sudo docker run -d --name db /postgres
--name flag để chỉ định tên của container.
Sau đó chạy web app bằng câu lệnh:
sudo docker run -d -P --name web --link db:db linuxhjkaru/test-app:v1
--link flag để link container.

4. Vài vấn đề về container IP address

Khi Docker được chạy thì nó sẽ tạo ra một virtual interface có tên là docker0. Docker sẽ chọn dải IP mà chưa được sử dụng trong host để gán cho docker0, và dải IP thường được sử dụng là 172.17.42.1/16. Có thể kiểm tra bằng câu lệnh:
/sbin/ifconfig docker0

docker0   Link encap:Ethernet  HWaddr 56:84:7a:fe:97:99
          inet addr:172.17.42.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::5484:7aff:fefe:9799/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:246 errors:0 dropped:0 overruns:0 frame:0
          TX packets:240 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:16753 (16.7 KB)  TX bytes:30112 (30.1 KB)

Không chỉ là một virtual interface, docker0 còn là một virtual Ethernet bridge với nhiệm vụ là chuyển các packet giữa container và host, và giữa các container với nhau.

Để có thể truy cập vào container, cần phải có IP address của container đó. Lấy IP Address của docker thì chạy câu lệnh sau:
sudo docker inspect furious_thompson | grep IPAddress

Trong câu lệnh trên thì furious_thompson là tên của container (có thể thay bằng Container ID). Câu lệnh inspect sẽ cho chúng ta toàn bộ thông tin của Container đang chạy như ruby version, RAILS_ENV, địa chỉ MAC, IP của container...

...
"Env": [
            "HOME=/root",
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "RUBY_MAJOR=2.1",
            "RUBY_VERSION=2.1.2",
            "RAILS_ENV=development"
        ],
...
"NetworkSettings": {
        "Bridge": "docker0",
        "Gateway": "172.17.42.1",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "IPAddress": "172.17.0.3",
...

Ở mục 2 chúng ta đã truy cập vào trang web bằng địa chỉ: http://localhost:80 (sử dụng port 80 của Docker). Nếu như đã biết container ip thì có thể truy cập vào địa chỉ container-ip:3000 (sử dụng port 3000 của rails) và sẽ thấy trang web của chúng ta hiện ra.

Tương tự như trong mục 3 có thể link với container của database bằng cách sử dụng địa chỉ ip của database container. Tuy nhiên trong trường hợp này khi tạo image của database cần có các thiết lập cần thiết để chuyển packet mà container nhận được về địa chỉ của database bên trong container.

0