I.Tổng quan về docker
I.1 Khái niệm về docker
Docker là một hệ thống mã nguồn mở, hỗ trợ đóng gói và tự động triển khai phần mềm trong các container. Nó cung cấp một cách nhanh, gọn để tạo môi trường hoạt động cho phần mềm, giảm thiểu rủi ro giữa dev và ops khi developper phát triển trên cùng một môi trường như môi trường vận hành, giúp dễ dàng tự động hóa và tăng tốc chu trình phát triển phần mềm (dev, test, deploy…).
Ưu điểm:
- Triển khai ứng dụng nhanh chóng : container bao gồm các yêu cầu tối thiểu để chạy của ứng dụng , làm giảm kích thước của chúng và cho phép chúng được triển khai nhanh chóng .
- Khả năng di chuyển linh động : một ứng dụng và tất cả các phụ thuộc của nó có thể được gói vào một container duy nhất , độc lập với các phiên bản máy chủ của Linux kernel , phân phối nền tảng , hoặc mô hình triển khai.Container này có thể được chuyển sang một máy chạy Docker, và được thực hiện mà không hề có vấn đề tương thích hay không.
- Kiểm soát phiên bản và tái sử dụng.
- Dễ dàng chia sẻ : với Docker Hub hoặc 1 public Registry việc chia sẻ container rất dễ dàng thực hiện và thân thiện với mọi người kể cả developer, tester, admin system.
- Nhẹ và chi phí tối thiểu : Docker image thường rất nhỏ , tạo điều kiện cho việc kiểm thử và giảm thời gian để triển khai các ứng dụng mới container.
I.2 Khi nào sử dụng docker
- Tách biệt các cài đặt cho từng ứng dụng, không gây ảnh hưởng lẫn nhau.
- Xây dựng môi trường làm việc mà không quá tốn nhiều thời gian cho việc cài đặt.
- Đồng nhất môi trường phát triển.
- Đóng gói môi trường thực thi một cách nhỏ gọn kèm theo cho dự án.
I.3 Kiến trúc của Docker
Docker sử dụng kiến trúc client-server:
- Client: Là bộ công cụ ở dạng dòng lệnh dùng để pull/push/search các templates dựng sẵn từ registry công cộng hoặc riêng một tổ chức nào đó thông qua Restful API và tập hợp các lệnh khác để tương tác với container.
- Server: chạy trên nền hệ điều hành của máy chủ dưới dạng một daemon, chịu trách nhiệm cho các tác vụ như đóng gói, thực thi, tải về container image.
I.4 Các thành phần của docker
Docker được tạo bởi 3 phần chính : Container, Image, Registry
- Container: dùng để tách biệt ứng dụng và các thành phần thưc thi của ứng dụng đó với các container khác trên cùng 1 máy chủ và với chính máy chủ chứa container đó.
- Image: là các template dựng sẵn đã chứa đủ các thành phần của môi trường thực thi cần cho ứng dụng và được dùng để tạo các container. Chẳng hạn một image chứa hệ điều hành Ubuntu đã cài đặt sẵn Apache và ứng dụng web
- Registry : Là kho chứa images. Người dùng có thể tạo ra các images của mình và tải lên đây hoặc tải về các images được chia sẻ (Docker Hub)
Hình 1.1 Mô hình tương tác giữa các thành phần docker
Docker Daemon
Như thế hiện trên hình vẽ , Docker daemon chạy trên các máy host. Người dùng sẽ không tương tác trực tiếp với các daemon, mà thông qua Docker Client.
Docker Client
Là giao diện người dùng của Docker, nó cung cấp cho người dùng giao diện dòng lệnh và thực hiện phản hồi với các Docker daemon.
Docker images
Là một template chỉ cho phép đọc, ví dụ một image có thể chứa hệ điều hành Ubuntu và web app. Images được dùng để tạo Docker container. Docker cho phép chúng ta build và cập nhật các image có sẵn một cách cơ bản nhất, hoặc bạn có thể download Docker images của người khác.
Docker Container
Docker container có nét giống với các directory. Một Docker container giữ mọi thứ chúng ta cần để chạy một app. Mỗi container được tạo từ Docker image. Docker container có thể có các trạng thái run, started, stopped, moved và deleted.
I.5 Sự khác nhau giữa Docker và Máy Ảo
Hình 1.2 Mô hình docker và máy ảo
- Cùng xét mô hình kiến trúc của VM: Mỗi ứng dụng được ảo hóa bao gồm chính ứng dụng đấy và cũng chứa các phụ thuộc của nó giống như bên container. Tuy nhiên bên VM sẽ kèm theo thêm 1 guest OS. Điều này dẫn tới việc đóng gói ứng dụng được ảo hóa sẽ có dung lượng lên tới hàng GB.
- Khác với container là chia sẻ host OS đồng nghĩa với việc các container sẽ có OS giống nhau thì với máy ảo, mỗi một VM có thể có OS khác so với các VM khác và thậm trí OS của các VM hoàn toàn có thể khác với host OS.
- Xét về tính linh hoạt: Nếu như bạn muốn bảo trì máy host, với container thì khi bảo trì mà buộc phải khởi động lại máy thì đồng nghĩa với việc hoạt động của các container có trong máy đó sẽ bị gián đoạn. Tuy nhiên với VM, bạn hoàn toàn có thể di chuyển các VM có trong máy cần được bảo dưỡng sang tạm các máy tính khác. Điều này giúp ứng dụng có trong các VM hoạt động mà không bị gián đoạn.
- Xét về tính an toàn: Với container, do dùng chung OS nên nếu có lỗ hổng nào đấy ở kernel của host OS thì nó sẽ ảnh hưởng tới toàn bộ container có trong host OS đấy
- Sử dụng Docker tạo và xóa container nhanh, dễ dàng, trong khi Virtual Machine yêu cầu cài đặt đầy đủ và sử dụng nhiều tài nguyên của máy để thực thi việc cài đặt đó
- Container ưu điểm là lightweight, có thể chạy nhiều container hơn VM khi triển khai trên cùng một máy chủ. Container bật tắt nhẹ nhành, nhanh chóng
- VM có thể migrate giữa các máy chủ trong lúc chạy. Container thì phải dừng hẳn thì mới migrate được.
- Hypervisor có thời gian khởi động trung bình là 20s, thay đổi phụ thuộc vào tốc độ của ổ đĩa.
- Containers khởi động và làm cho ứng dụng sẵn sàng chạy trong 500ms, mang lại tính khả thi cao cho những dự án cần sự mở rộng nhanh.
I.6 Quy trình thực thi của một hệ thống sử dụng Docker.
Như hình vẽ trên , một hệ thống Docker được thực thi với 3 bước chính :
Build -> Push -> Pull,Run
a, Build.
Đầu tiên chúng ta sẽ tạo một dockerfile, trong dockerfile này chính là code của chúng ta.
Dockerfile này sẽ được Build tại một máy tính đã cài đặt Docker Engine.
Sau khi build ta sẽ thu được Container, trong Container này chứa bộ thư viện và ứng dụng của chúng ta.
b, Push.
Sau khi có được Container, chúng ta thực hiện push Container này lên đám mây và lưu trữ ở đó.Việc push này có thể thực hiện qua môi trường mạng Internet.
c, Pull, Run
Giả sử một máy tính muốn sử dụng Container chúng ta đã push lên đám mây (máy đã cài Docker Engine) thì bắt buộc máy phải thực hiện việc Pull container này về máy. Sau đó thực hiện Run Container này.
II.Cấu trúc của một Docker File
II.1 Docker File
Dockerfile là 1 file text chứa các lệnh thực thi để build 1 image cho docker. Với dockerfile chúng ta có 1 phương tiện để build các image 1 cách tự động và share với nhau 1 cách dễ dàng, 1 team của 1 dự án có thể dung dockerfile để tạo các môi trường dev và test đồng nhất với nhau
II.2 Cấu trúc tập lệnh của một Docker File
+ FROM <image>
Đây là lệnh phải có với bất kỳ 1 dockerfile nào, và phải nằm ở line đầu tiên của file
Mục đích của lệnh là set image làm cơ sở để từ đó tạo nên image muốn build
Ví dụ: FROM ubuntu:12.04
=>Nếu image cơ sở này không tồn tại trong local thì docker sẽ tự pull image này từ Docker Hub
+ MAINTAINER <name>
Lệnh dùng để set tác giả của image, có thể có hoặc không
+ RUN <command>
Lệnh dùng để thực thi 1 command trên hệ thống(của image)
+ CMD <command>
Trong 1 dockerfile chỉ có thể có 1 lệnh CMD. Lệnh này để tạo command được thưc thi khi khởi chạy image
+ ADD <src> <dest>
Lệnh dùng để copy file từ remote hoặc local file được chỉ định ở <src> vào path trên container được chỉ đinh ở <dest>
+ EXPOSE <port> [<port>]
Lệnh dùng để chỉ định rằng containner của image sẽ listen trên các port nào đó trong khi chạy
III. Một số tập lệnh làm việc với Docker ( Docker Engine)
+Pull một image từ Docker Hub
$ docker pull {image_name}
+Liệt kê các images hiện có
$ docker images
+Xóa một image
$ docker rmi {image_id/name}
+Liệt kê các container đang chạy
$ docker ps
$ docker ps -a #Liệt kê các container đã tắt
+Xóa một container
$ docker rm -f {container_id/name}
+Đổi tên một container
$ docker rename {old_container_name} {new_container_name}
+Khởi động một container
$ docker start {new_container_name}
$ docker exec -it {new_container_name} /bin/bash
+Tạo mới một container, đồng thời khởi động với tùy chọn cổng và volume
$ docker run –name {container_name} -p {host_port}:{container_port} -v {/host_path}:{/container_path} -it {image_name} /bin/bash
+Xem các thay đổi trên container
$ docker diff {container_name}
+Commit các thay đổi trên container và image
$ docker commit -m “message” {container_name} {image_name}
+Save image thành file .tar
$ docker save {image_name} > {/host_path/new_image.tar}
+Tạo một image mới từ file .tar
$ cat musashi.tar | docker import – {new_image_name}:latest
+Xem lịch sử các commit trên image
$ docker history {image_name}
+Khôi phục lại images từ IMAGE_ID
$ docker tag {iamge_id} {image_new_name}:{tag}
+Build một image từ container
$ docker build -t {container_name} .
Dấu . ở đây có thể hiểu là Dockerfile đang nằm trong thư mục hiện tại.
Tham khảo phần demo tạo 1 Docker file & container qua link github sau:
https://github.com/lieunn/docker-lamp
IV. Docker Storage
Volume trong Docker
=>Volume trong Docker được dùng để chia sẻ dữ liệu cho container. Để sử dụng volume trong docker dùng cờ hiệu (flag) -v trong lệnh docker run.
Có thể sử dụng Volume trong Docker trong những trường hợp sau
- Chia sẻ giữa container và container.
- Chia sẻ giữa container và host.
- Sử dụng volume để gắn (mount) một thư mục nào đó trong host với container.
Sử dụng volume để chia sẻ dữ liệu giữa host và container
Trong tình huống này thư mục trên máy host (máy chứa container) sẽ được mount với một thư mục trên container, dữ liệu sinh ra trên thư mục được mount của container sẽ xuất hiện trên thư mục của host.
* Có 2 chế độ chia sẻ volume trong docker, đó là read-write (rw) hoặc read-only (ro). Nếu không chỉ ra cụ thể thì mặc định sử dụng chế độ read-write. Ví dụ chế độ read-only, sử dụng tùy chọn ro.
$ docker run -it -v $(pwd)/bindthis:/var/www/html/webapp:ro ubuntu bash
Các lưu ý về volume trong Docker
- Đường dẫn trong cờ hiệu -v phải là đường dẫn tuyệt đối, thường dùng $(pwd)/ten_duong_dan để chỉ đúng đường dẫn.
- Có thể chỉ định việc mount giữa thư mục trên host và thư mục trên container ở các chế độ read-wirte hoặc read-only, mặc định là read-write.
- Để chia sẻ volume dùng tùy chọn –volumes-from
Sử dụng Docker với một số storage khác
=>Nhu cầu về lưu trữ data ngày càng tăng => cần 1 giải pháp storage hợp lý, có thể kể đến Ceph, Glusterfs, Openfiler ….
=> Có thể xây dựng một hệ thống storage ceph, gluster tách riêng sau đó sẽ mount các volume share tương ứng về volume local trên docker container
Hình 3.1.Mô hình lưu trữ Ceph-Docker
Như hình trên thì ta sẽ xây dựng một hệ thống ceph cluster chứa các volume cần share, client sẽ xây dựng 2 host docker để map volume share về local và mount vào các docker container
+ Một số bài viết tham khảo:
http://hustcat.github.io/run-docker-on-ceph/
https://hub.docker.com/r/ceph/rbd-volume/
https://hub.docker.com/r/jsafrane/glusterfs-mounter
V. Network Docker
- Cấu trúc của Virtual Bridge
Network của docker được quản lý thông qua một virtual bridge gọi là docker0. Mục đích của việc này là để tạo ra một network độc lập, tách biệt với môi trường khác.
Khi chúng ta khởi động docker deamon (thông qua sudo service docker startchẳng hạn) thì những step dưới đây sẽ diễn ra:
+ Virtual bridge docker0 sẽ được tạo ra=>Docker tự dộng tìm ra một khoảng ip range còn trống từ trong route của máy host=>Chọn ra random một khoảng ip bất kì=>Assign khoảng ip đó cho docker0
Sau đó khi chúng ta khởi động một container bất kì, thì container đó sẽ được assign những thứ dưới đây:
+ veth (Virtual Eithernet) interface gắn với docker0
+ một ip bất kì trong range mà docker0 vừa thu được ở trên
- Networking giữa các container với nhau
Để kiểm soát việc các container có làm việc được với nhau hay không, chúng ta thông qua parameter -icc của docker daemon.
+ Khi -icc = true thì container có thể nói chuyện được với nhau.
+ Khi -icc = false thì các container sẽ bị tách biệt với nhau
Ngoài ra để public một port nào đó ra ngoài chúng ta cũng phải chỉ định EXPOSE <port> trong Dockerfile hoặc là –expose <port> khi khởi động container.
Cụ thể hơn, để các container nói chuyện được với nhau, docker0 sử dụng một tính năng gọi là –link. Khi khởi động một container nào đó chúng ta phải chỉ định –link containerName:containerAlias , nhờ đó mà service trong container đó sẽ tìm thấy service muốn kết nối đến thông qua biến môi trường.
- Kết nối từ network ở ngoài vào container
Để kết nối từ network ở ngoài vào container thì chúng ta phải mapping port của máy host với port mà container expose thông qua docker0.
Ví dụ chúng ta muốn map port 8080 của máy host vào port 80 của docker , sử dụng apache container:
$ ID=$(docker run -d -p 8080:80 tcnksm/apache)
caad0cfc2a0
Chúng ta có thể kiểm tra mapping như sau
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
caad0cfc2a03 tcnksm/apache:latest /usr/sbin/apache2 -D About a minute ago Up About a minute 0.0.0.0:8080->80/tcp elegant_thompson
$ docker port $ID 80
0.0.0.0:8080
$ ID=$(docker run -d -p 80 tcnksm/apache)
$ docker port $ID 80
0.0.0.0:49156
$ curl `docker port $ID 80`
Hello, docker
4. Bridge network trong Docker
Về native, docker hỗ trợ 3 loại network:
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER
f163f5a13de0 bridge bridge
4cf5b3a8120b host host
d33d2260ad2c none null
=>Mặc định, docker dùng bridge network. Khi cài đặt docker, bạn sẽ thấy một interface docker0 trên host. Khi khởi chạy một container trong host, một interface mới đại diện cho nó sẽ được sinh ra trên host:
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:f1:59:1a:46 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:f1ff:fe59:1a46/64 scope link
valid_lft forever preferred_lft forever
92: vethc4c9915@if91: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether de:bf:41:5b:54:f6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::dcbf:41ff:fe5b:54f6/64 scope link
valid_lft forever preferred_lft forever
=>Có thể xem ip của docker container qua:
[root@localhost ~]# docker inspect 992f2635e59f | grep IPAddr
“SecondaryIPAddresses”: null,
“IPAddress”: “172.17.0.2”,
“IPAddress”: “172.17.0.2”,
Tất cả các container đều nhận host làm gateway.Do các container đều dùng host làm gateway nên bridge network cho phép:
+ Container trên cùng host giao tiếp với nhau được
+ Container có thể gửi packet ra bên ngoài host được.
=>Để đảm bảo host forward được IP thì cần cấu hình NAT và cho phép ip forward.
Trên host cấu hình ip forward:
vi /etc/sysctl.conf
net.ipv4.conf.all.forwarding = 1
sysctl -p
[root@localhost Docker_Centos6]# docker run -it -p 81:80 image_name
ở đây port trong container 80 sẽ được map đến 81 trong host.
Có thể tham khảo chi tiết hơn ở link sau:
http://kipalog.com/posts/Co-ban-ve-docker-network
VI. Docker-Compose
Compose là công cụ giúp định nghĩa và khởi chạy multi-container Docker applications. Trong Compose, chúng ta sử dụng Compose file để cấu hình application’s services. Chỉ với một câu lệnh, lập trình viên có thể dễ dàng create và start toàn bộ các services phục vụ cho việc chạy ứng dụng.
- Compose là một công cụ tuyệt vời không chỉ dùng cho development, testing, staging environments, mà còn ứng dụng trong CI workflows. Việc sử dụng Docker Compose được tóm lược trong 3 bước cơ bản sau:
- Khai báo app’s environment với Dockerfile.
- Khai báo các services cần thiết để chạy app trong docker-compose.yml.
- Run docker-compose up và Compose sẽ start và run app.
Setup Docker-Compose tham khảo qua link github sau:
https://github.com/lieunn/docker-compose
VII. Docker-Swarm
Docker swarm là một công cụ giúp chúng ta tạo ra một clustering Docker. Nó giúp chúng ta gom nhiều Docker Engine lại với nhau và ta có thể “nhìn” nó như duy nhất một virtual Docker Engine.
- Trong phiên bản v1.12.0, Docker Swarm là một tính năng được tích hợp sẵn trong Docker Engine.
Trong phần này, tôi sẽ tạo ra 1 cụm cluster gồm 1 manager và 2 worker chạy dịch vụ web-server.
- node manager sẽ là node quản lý cluster.
- node worker là các node chạy dịch vụ. Nếu mà node worker die thì node manager sẽ run container trên chính nó.
Tham khảo mô hình setup sau:
- https://github.com/lieunn/summary-docker/blob/master/docs/docker-swarm.md
- https://asciinema.org/a/94625 ( deploy production)
VIII. Monitoring Docker
Giám sát tình trạng trên docker host
Có thể tham khảo bài viết sau:
https://github.com/monitoringartist/zabbix-docker-monitorin
http://logz.io/blog/docker-monitoring-dockercon-2016/
https://stefanprodan.com/2016/a-monitoring-solution-for-docker-hosts-containers-and-containerized-services/
Tìm hiểu về Docker Containers và Azure Container Service (Phần 1)
https://blog.nimbleci.com/2016/08/17/how-to-set-up-and-deploy-to-a-1000-node-docker-swarm/
https://www.vishnu-tech.com/blog/
https://viblo.asia/p/cac-van-de-ve-docker-tren-production-DzVkpmMwvnW
Docker cho người mới bắt đầu (P1)
https://blog.topdev.vn/su-dung-docker-va-ca-docker-compose-cho-du-an-django/
https://viblo.asia/p/tai-sao-nen-dua-docker-lam-chuan-khi-phat-trien-MdZkAYBakox