Docker toàn tập

Docker là gì?

Wikipedia định nghĩa Docker:

Docker là một dự án mã nguồn mở tự động hóa việc triển khai các ứng dụng phần mềm bên trong các container bằng cách cung cấp thêm một tầng trừu tượng hóa và tự động hóa của ảo hóa cấp hệ điều hành trên Linux.

Nói một cách đơn giản hơn, Docker là một công cụ cho phép các nhà phát triển, quản trị hệ thống, v.v ... dễ dàng triển khai các ứng dụng của họ trong một container để chạy trên bất kỳ máy chủ nào.

Lợi ích chính của Docker là cho phép người dùng đóng gói một ứng dụng với tất cả các phụ thuộc của nó vào một đơn vị được tiêu chuẩn hóa để phát triển phần mềm.

Không giống như các máy ảo, các container sử dụng ít tài nguyên hơn và do đó cho phép sử dụng hiệu quả hơn các tài nguyên hệ thống.

Container là gì?

Tiêu chuẩn công nghiệp ngày nay là sử dụng máy ảo (VM) để chạy các ứng dụng phần mềm. Máy ảo chạy các ứng dụng trên phần cứng ảo hóa được cung cấp bởi máy chủ.

Máy ảo cô lập toàn bộ tiến trình cho các ứng dụng rất tốt. Rất hiếm khi sự cố trong máy chủ có thể ảnh hưởng đến phần mềm đang chạy trong máy ảo và ngược lại.

Nhưng sự cô lập này có chi phí rất lớn - phần cứng ảo hóa cho một hệ điều hành của máy ảo sử dụng là rất đáng kể.

Các container có một cách tiếp cận khác: bằng cách tận dụng các cơ chế cấp thấp của hệ điều hành máy chủ, các container cung cấp hầu hết sự cô lập của máy ảo chỉ với một phần nhỏ sức mạnh của hệ thống.

Tại sao nên sử dụng container?

Các container cung cấp một cơ chế đóng gói hợp lý trong đó các ứng dụng có thể được trừu tượng hóa từ môi trường mà chúng thực sự chạy.

Việc tách rời này cho phép các ứng dụng dựa trên container được triển khai dễ dàng và nhất quán, bất kể môi trường đích là trung tâm dữ liệu riêng, đám mây công cộng hay thậm chí là máy tính xách tay cá nhân của nhà phát triển.

Điều này cung cấp cho các nhà phát triển khả năng tạo các môi trường có thể dự đoán để tách biệt với phần còn lại của ứng dụng và có thể chạy ở bất cứ đâu.

Từ quan điểm hoạt động, ngoài tính di động các container còn kiểm soát các tài nguyên tốt hơn giúp mang lại hiệu quả cải thiện cơ sở hạ tầng của bạn, điều này có thể giúp sử dụng tốt hơn các tài nguyên hệ thống của bạn.

Google Trends cho Docker

Do những lợi ích này, container (và Docker) đã được áp dụng rộng rãi. Các công ty như Google, Facebook, Netflix và Salesforce đã tận dụng các container để làm cho các nhóm kỹ thuật lớn làm việc hiệu quả hơn và cải thiện việc sử dụng tài nguyên hệ thống.

Trên thực tế, Google đã dùng các container để loại bỏ nhu cầu về trung tâm dữ liệu.

Hướng dẫn này sẽ dạy bạn điều gì?

Hướng dẫn này nhằm mục đích trở thành nơi duy nhất giúp bạn tìm hiểu đầy đủ mọi thứ về Docker.

Ngoài việc làm sáng tỏ mọi thứ về Docker, nó sẽ cung cấp cho bạn trải nghiệm thực tế với việc xây dựng và triển khai các ứng dụng web của riêng bạn trên đám mây.

Chúng tôi sẽ sử dụng Amazon Web Services để triển khai một trang web tĩnh, và hai webapps động trên EC2 sử dụng Elastic BeanstalkElastic Container Service.

Ngay cả khi bạn không có kinh nghiệm trước khi triển khai, hướng dẫn này sẽ là tất cả những gì bạn cần để bắt đầu.

BẮT ĐẦU

Tài liệu này chứa một loạt các phần, mỗi phần giải thích một khía cạnh cụ thể của Docker.

Trong mỗi phần, chúng ta sẽ gõ các lệnh (hoặc viết mã). Tất cả các mã được sử dụng trong hướng dẫn có sẵn trong repo Github.

Lưu ý: Hướng dẫn này sử dụng phiên bản Docker 18.05.0-ce. Nếu bạn thấy bất kỳ phần nào của hướng dẫn không tương thích với phiên bản trong tương lai, vui lòng cho chúng tôi biết bằng cách để lại comment ở cuối bài viết. Cảm ơn!

Điều kiện tiên quyết

Không bắt buộc phải có kỹ năng cụ thể cần thiết cho hướng dẫn này ngoại trừ kỹ năng sử dụng dòng lệnh cơ bản và sử dụng trình soạn thảo văn bản.

Hướng dẫn này sử dụng lệnh git clone để tải dự án từ Github về máy của bạn. Nếu bạn chưa cài đặt Git trên hệ thống của mình, hãy cài đặt nó hoặc bạn cũng có thể tải xuống thủ công file zip của dự án từ Github.

Kinh nghiệm trước đây trong việc phát triển các ứng dụng web sẽ hữu ích nhưng không bắt buộc.

Khi thực hiện hướng dẫn này, chúng tôi sẽ sử dụng một vài dịch vụ đám mây. Nếu bạn quan tâm, vui lòng tạo một tài khoản trên mỗi trang web sau để tiện theo dõi:

Thiết lập máy tính của bạn

Việc thiết lập tất cả các công cụ trên máy tính của bạn có thể là một nhiệm vụ khó khăn.

Nhưng may mắn là Docker bây giờ đã rất ổn định giúp việc chạy nó trên hệ điều hành yêu thích của bạn đã trở nên rất dễ dàng.

Cho đến một vài bản phát hành trước đây, việc chạy Docker trên OSX và Windows khá rắc rối.

Tuy nhiên, gần đây Docker đã đầu tư đáng kể vào việc cải thiện trải nghiệm trên máy tính của người dùng trên các hệ điều hành này. Do đó, việc chạy Docker bây giờ rất đơn giản.

Các hướng dẫn bắt đầu về Docker đã hướng dẫn chi tiết cho việc thiết lập Docker trên Mac , LinuxWindows.

Khi bạn đã hoàn tất cài đặt Docker, hãy kiểm tra cài đặt Docker của bạn bằng cách chạy lệnh sau:


$ docker run hello-world

Hello from Docker.
This message shows that your installation appears to be working correctly.
...

Nếu nhận được kết quả như trên là bạn đã cài đặt Docker thành công rồi.

HELLO WORLD

Chơi với Busybox

Bây giờ chúng ta đã thiết lập xong mọi thứ, đã đến lúc thực hành rồi. Trong phần này, chúng tôi sẽ chạy container Busybox trên hệ thống của chúng tôi và trải nghiệm câu lệnh docker run.

Để bắt đầu, hãy chạy lệnh sau trong cửa sổ dòng lệnh của bạn:


$ docker pull busybox
Lưu ý: Tùy thuộc vào cách bạn đã cài đặt docker trên hệ thống của mình, bạn có thể thấy lỗi permission denied sau khi chạy lệnh trên. Nếu bạn đang sử dụng máy Mac, hãy đảm bảo Docker đang chạy. Nếu bạn đang dùng Linux, thì hãy thêm tiền tố sudo vào các lệnh docker của bạn. Ngoài ra, bạn cũng có thể tạo một nhóm docker để không gặp vấn đề này.

Lệnh pull lấy image busybox từ Docker registry và lưu nó vào hệ thống của chúng tôi. Bạn có thể sử dụng lệnh docker images để xem danh sách tất cả các image trên hệ thống của bạn.


$ docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
busybox                 latest              c51f86c28340        4 weeks ago         1.109 MB

Docker Run

Tuyệt quá! Bây giờ chúng ta hãy chạy một Docker container dựa trên image này. Để làm điều đó, chúng ta sẽ sử dụng lệnh docker run.


$ docker run busybox

Đợi đã, không có gì xảy ra! Đó có phải là một lỗi không? Ồ không phải lỗi đâu. Đã có rất nhiều thứ xảy ra ở phía sau.

Khi bạn gọi lệnh run, Docker Client tìm thấy hình ảnh (busybox trong trường hợp này) và tải nó lên container và sau đó chạy một lệnh trong container đó.

Khi chúng tôi chạy lệnh docker run busybox, chúng tôi không cung cấp một lệnh cho container busybox, vì vậy container đã khởi động, chạy một lệnh trống và sau đó thoát ra. Hãy thử lại với lệnh sau:


$ docker run busybox echo "hello from busybox"
hello from busybox

Tuyệt vời - cuối cùng chúng ta cũng thấy kết quả đầu ra. Trong trường hợp này, Docker Client chạy lệnh echo trong container busybox của chúng ta và sau đó thoát ra.

Nếu bạn nhận thấy, tất cả điều đó đã xảy ra khá nhanh. Hãy tưởng tượng khởi động một máy ảo, chạy một lệnh và sau đó thoát ra. Bây giờ bạn biết tại sao họ nói container thì nhanh!

Ok, bây giờ là lúc để xem lệnh docker ps. Lệnh docker ps sẽ hiển thị cho bạn tất cả các container hiện đang chạy.


$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Vì không có container nào đang chạy, chúng tôi thấy một dòng trống. Hãy thử một phiên bản khác của câu lệnh với tham số -a: docker ps -a


$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
305297d7a235        busybox             "uptime"            11 minutes ago      Exited (0) 11 minutes ago                       distracted_goldstine
ff0a5c3750b9        busybox             "sh"                12 minutes ago      Exited (0) 12 minutes ago                       elated_ramanujan
14e5bd11d164        hello-world         "/hello"            2 minutes ago       Exited (0) 2 minutes ago                        thirsty_euclid

Như vậy, những gì chúng ta thấy ở trên là một danh sách tất cả các container mà chúng ta đã chạy.

Hãy lưu ý rằng cột STATUS cho thấy những container này đã thoát ra vài phút trước.

Bạn có thể tự hỏi nếu có một cách để chạy nhiều hơn chỉ một lệnh trong một container. Hãy thử ngay bây giờ:


$ docker run -it busybox sh
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # uptime
 05:45:21 up  5:58,  0 users,  load average: 0.00, 0.01, 0.04

Chạy lệnh run với các cờ -it gắn chúng ta với một tty tương tác trong container. Bây giờ chúng ta có thể chạy nhiều lệnh trong container như chúng ta muốn. Hãy dành chút thời gian để chạy các lệnh yêu thích của bạn.

Khu vực nguy hiểm: Nếu bạn cảm thấy đặc biệt thích phiêu lưu, bạn có thể thử lệnh rm -rf bin trong container. Hãy chắc chắn rằng bạn chạy lệnh này trong container chứ không phải trong máy tính xách tay / máy tính để bàn của bạn. Làm điều này sẽ làm cho bất kỳ lệnh nào khác như ls, uptime không hoạt động. Khi mọi thứ ngừng hoạt động, bạn có thể thoát khỏi container (gõ exit và nhấn Enter) và sau đó khởi động lại bằng lệnh docker run -it busybox sh. Vì Docker tạo một container mới mỗi lần, mọi thứ sẽ bắt đầu hoạt động trở lại.

Như vậy là chúng ta đã tìm hiểu xong câu lệnh docker run, nó có thể là lệnh bạn sẽ sử dụng thường xuyên nhất.

Để tìm hiểu thêm về run, sử dụng lệnh docker run --help để xem danh sách tất cả các cờ mà nó hỗ trợ. Khi chúng ta tiến xa hơn, chúng ta sẽ thấy một vài phiên bản khác của lệnh docker run.

Trước khi chúng ta tiếp tục, hãy tìm hiểu về việc xóa các container. Như đã trình bày ở trên, chúng ta vẫn thấy các container tồn tại ngay cả khi chúng ta đã thoát bằng cách chạy lệnh docker ps -a.

Trong suốt hướng dẫn này, bạn sẽ chạy lệnh docker run nhiều lần và tạo ra các container không sử dụng sẽ ngốn dung lượng ổ đĩa.

Do đó, tôi sẽ dọn sạch các container sau khi đã sử dụng chúng. Để làm điều đó, bạn có thể chạy lệnh docker rm. Chỉ cần sao chép container ID từ phía trên và dán chúng vào câu lệnh như sau:


$ docker rm 305297d7a235 ff0a5c3750b9
305297d7a235
ff0a5c3750b9

Bạn sẽ phải tìm container ID khi xóa container. Nếu bạn có một loạt các container để xóa trong một lần thì việc tìm và copy các container ID có thể rất tẻ nhạt. Trong trường hợp đó, bạn chỉ cần chạy lệnh sau:


$ docker rm $(docker ps -a -q -f status=exited)

Lệnh này xóa tất cả các container có trạng thái exited. Cờ -q trả về container ID và cờ -f là bộ lọc đầu ra dựa trên các điều kiện được cung cấp.

Một điều cuối cùng rất hữu ích là cờ --rm có thể được truyền vào lệnh docker run để tự động xóa container sau khi nó thoát ra. Đối với một lần chạy docker, cờ --rm rất hữu ích.

Ngoài ra, lệnh docker container prune có thể được sử dụng để đạt được điều tương tự.


$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
4a7f7eebae0f63178aff7eb0aa39f0627a203ab2df258c1a00b456cf20063
f98f9c2aa1eaf727e4ec9c0283bcaa4762fbdba7f26191f26c97f64090360

Total reclaimed space: 212 B

Cuối cùng, bạn cũng có thể xóa các image mà bạn không còn cần bằng cách chạy lệnh docker rmi.

Thuật ngữ

Trong phần trước, chúng tôi đã sử dụng rất nhiều thuật ngữ dành riêng cho Docker có thể gây nhầm lẫn cho một số người.

Vì vậy, trước khi chúng ta đi xa hơn, hãy để tôi làm rõ một số thuật ngữ được sử dụng thường xuyên trong hệ sinh thái Docker.

  • Image - Bản thiết kế của ứng dụng của chúng tôi tạo thành cơ sở của các container. Trong bản demo ở trên, chúng tôi đã sử dụng lệnh docker pull để tải xuống image busybox .
  • Container - Được tạo từ Docker Image và chạy ứng dụng thực tế. Chúng tôi tạo một container bằng cách sử dụng lệnh docker run image busybox mà chúng tôi đã tải xuống. Có thể xem danh sách các container đang chạy bằng cách sử dụng lệnh docker ps.
  • Docker Daemon - Dịch vụ nền chạy trên máy chủ quản lý việc xây dựng, chạy và phân phối các container Docker. Daemon là tiến trình chạy trong hệ điều hành để giao tiếp với các client.
  • Docker Client - Công cụ dòng lệnh cho phép người dùng tương tác với Daemon. Tổng quát hơn, cũng có thể có các dạng client khác - chẳng hạn như Kitical cung cấp GUI (giao diện đồ họa người dùng) cho người dùng.
  • Docker Hub - Một sổ đăng ký Docker Image. Bạn có thể nghĩ về sổ đăng ký như một thư mục của tất cả các Docker Image có sẵn. Nếu cần, người ta có thể lưu trữ các sổ đăng ký Docker Image của riêng họ và có thể sử dụng chúng để tải image.

WEBAPPS VỚI DOCKER

Tuyệt quá! Chúng ta đã tìm hiểu về lệnh docker run, chơi với busybox - một Docker container và một số thuật ngữ.

Bây giờ chúng ta đã sẵn sàng để làm việc thực tế với Docker, tức là triển khai các ứng dụng web với Docker!

Trang web tĩnh

Hãy bắt đầu bằng cách thực hiện các bước nhỏ và đơn giản. Điều đầu tiên chúng ta sẽ tìm hiểu là làm thế nào chúng ta có thể chạy một trang web tĩnh đơn giản.

Chúng ta sẽ lấy một Docker Image từ Docker Hub, chạy container và xem việc chạy một máy chủ web dễ dàng như thế nào.

Hãy bắt đầu nào. Image mà chúng ta sẽ sử dụng là một single-page website mà tôi đã tạo cho mục đích của bản demo này và được lưu trữ trên sổ đăng ký - prakhar1989/static-site.

Chúng ta có thể tải xuống và chạy image trực tiếp bằng lệnh docker run. Như đã lưu ý ở trên, cờ --rm sẽ tự động xóa container khi thoát.


$ docker run --rm prakhar1989/static-site

Vì image chưa tồn tại trên máy nên đầu tiên Docker Client sẽ tìm nạp image từ sổ đăng ký và sau đó chạy image.

Nếu mọi việc suôn sẻ, bạn sẽ thấy một thông báo Nginx is running... trong cửa số dòng lệnh của mình.

Được rồi bây giờ máy chủ web đang chạy, làm thế nào để xem trang web? Nó đang chạy trên cổng nào? Và quan trọng hơn, làm thế nào để chúng ta truy cập vào container trực tiếp từ máy chủ của chúng ta? Nhấn Ctrl + C để dừng container.

Vâng, trong trường hợp này, máy khách không hiển thị bất kỳ cổng nào, vì vậy chúng ta cần chạy lại lệnh docker run để xuất bản các cổng.

Chúng ta cũng nên tìm cách để cửa sổ dòng lệnh của chúng ta không bị gắn vào container đang chạy. Bằng cách này, bạn có thể đóng cửa sổ dòng lệnh của mình và giữ cho container hoạt động. Đây được gọi là chế độ detached.


$ docker run -d -P --name static-site prakhar1989/static-site
e61d12292d69556eabe2a44c16cbd54486b2527e2ce4f95438e504afb7b02810

Trong lệnh trên, -d sẽ tách cửa sổ dòng lệnh của chúng ta, -P sẽ xuất bản tất cả các cổng được đưa ra thành các cổng ngẫu nhiên và cuối cùng --name dùng để đặt tên cho container.

Bây giờ chúng ta có thể thấy các cổng bằng cách chạy lệnh docker port [CONTAINER NAME]


$ docker port static-site
80/tcp -> 0.0.0.0:32769
443/tcp -> 0.0.0.0:32768

Bạn có thể truy cập http://localhost:32769 trong trình duyệt của bạn.

Lưu ý: Nếu bạn đang sử Docker Toolbox thì bạn có thể cần phải sử dụng lệnh docker-machine ip default để lấy IP.

Bạn cũng có thể chỉ định một cổng tùy chỉnh mà máy khách sẽ chuyển tiếp các kết nối đến container.


$ docker run -p 8888:80 prakhar1989/static-site
Nginx is running...
Chạy trang web tĩnh bằng Docker

Để dừng một container detached, hãy chạy lệnh docker stop bằng cách cung cấp container ID. Trong trường hợp này, chúng ta cũng có thể sử dụng tên static-site mà chúng ta đã sử dụng để bắt đầu container.


$ docker stop static-site
static-site

Thật đơn giản phải không nào. Để thực hiện điều này trên một máy chủ thực, bạn chỉ cần cài đặt Docker và chạy lệnh docker ở trên.

Bây giờ bạn đã biết cách chạy máy chủ web bên trong Docker Image, bạn sẽ tự hỏi - làm sao để tạo Docker Image? Đây là câu hỏi chúng ta sẽ khám phá trong phần tiếp theo.

Docker Image

Chúng ta đã thấy Image ở những phần trước, nhưng trong phần này chúng ta sẽ tìm hiểu sâu hơn về Docker Image là gì và xây dựng Image của chính chúng ta!

Cuối cùng, chúng ta sẽ sử dụng Image đó để chạy ứng dụng của trên máy của mình và triển khai trên AWS để chia sẻ nó với bạn bè của chúng ta!

Bạn có phấn khích không? Chúng ta bắt đầu nào!

Docker Image là nền tảng của container. Trong ví dụ trước, chúng ta đã kéo Image Busybox từ sổ đăng ký Docker để chạy một container dựa trên Image đó.

Sử dụng lệnh docker images để xem danh sách các image có sẵn trên máy.


$ docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
prakhar1989/catnip              latest              c7ffb5626a50        2 hours ago         697.9 MB
prakhar1989/static-site         latest              b270625a1631        21 hours ago        133.9 MB
python                          3-onbuild           cf4002b2c383        5 days ago          688.8 MB
martin/docker-cleanup-volumes   latest              b42990daaca2        7 weeks ago         22.14 MB
ubuntu                          latest              e9ae3c220b23        7 weeks ago         187.9 MB
busybox                         latest              c51f86c28340        9 weeks ago         1.109 MB
hello-world                     latest              0a6ba66e537a        11 weeks ago        960 B

Ở trên là danh sách các Image mà tôi đã kéo từ sổ đăng ký, cùng với những Image mà tôi đã tự tạo. TAG tham chiếu đến một snapshot cụ thể của Image và IMAGE ID là định danh duy nhất tương ứng cho Image đó.

Để đơn giản, bạn có thể hình dung Image gần giống với git repository - Image có thể được commit với các thay đổi và có nhiều phiên bản. Nếu bạn không cung cấp phiên bản cụ thể, client sẽ mặc định là latest. Ví dụ: bạn có thể kéo một phiên bản cụ thể của Image ubuntu như sau:


$ docker pull ubuntu:18.04

Để có được Image Docker mới, bạn có thể lấy nó từ sổ đăng ký (chẳng hạn như Docker Hub) hoặc tạo Image của riêng bạn.

Có hàng chục ngàn Image có sẵn trên Docker Hub. Bạn cũng có thể tìm kiếm hình ảnh trực tiếp từ dòng lệnh bằng cách sử dụng docker search.

Một sự khác biệt quan trọng cần lưu ý khi nói đến Image là sự khác biệt giữa Image cơ sở và Image con.

  • Image cơ sở là Image không có Image gốc, thường là Image hệ điều hành như ubuntu, busybox hoặc debian.
  • Image conImage được xây dựng trên Image cơ sở và thêm chức năng bổ sung.

Sau đó, có Image chính thức và Image người dùng:

  • Image chính thức là Image được duy trì và hỗ trợ chính thức bởi Docker. Thông thường chúng đường dẫn định dạng là _/image-name.
  • Image người dùng là Image được tạo và chia sẻ bởi những người dùng như bạn và tôi. Họ xây dựng dựa trên Image cơ sở và thêm các chức năng bổ sung. Thông thường chúng đường dẫn định dạng là user/image-name.

Image đầu tiên của chúng tôi

Bây giờ chúng ta đã hiểu rõ hơn về Image, đã đến lúc tạo ra hình ảnh của riêng chúng ta.

Mục tiêu của chúng ta trong phần này sẽ là tạo ra một Image để thử nghiệm ứng dụng Flask đơn giản.

Tôi đã tạo sẵn một ứng dụng Flask nho nhỏ thú vị hiển thị một con mèo ngẫu nhiên mỗi khi nó được tải. Nếu bạn chưa có source, vui lòng sao chép nó về máy của bạn bằng lệnh sau hoặc bạn cũng có thể tải về bằng file Zip trên Github:


$ git clone https://github.com/prakhar1989/docker-curriculum.git
$ cd docker-curriculum/flask-app
Source nên được sao chép về máy nơi bạn đang chạy các lệnh docker chứ không phải bên trong một container docker.

Bước tiếp theo bây giờ là tạo một Image cho ứng dụng web này. Như đã đề cập ở trên, tất cả các Image người dùng được dựa trên một Image cơ sở. Vì ứng dụng của chúng tôi được viết bằng Python, nên Image cơ sở chúng tôi sẽ sử dụng sẽ là Python 3.

Dockerfile

Dockerfile là một tập tin văn bản đơn giản có chứa một danh sách các lệnh mà Docker Client gọi trong khi tạo ra một Image. Đó là một cách đơn giản để tự động hóa quá trình tạo Image.

Một điểm tuyệt vời nữa là các lệnh bạn viết trong Dockerfile gần giống với các lệnh trong Linux. Điều này có nghĩa là bạn không thực sự phải học cú pháp mới để tạo các dockerfiles của riêng bạn.

Thư mục ứng dụng sẽ chứa Dockerfile nhưng vì lần đầu tiên chúng ta làm điều này nên chúng ta sẽ tạo nó.

Để bắt đầu, hãy tạo một file trống mới trong trình soạn thảo văn bản yêu thích của bạn và lưu nó vào cùng thư mục với ứng dụng flask với tên gọi là Dockerfile.

Chúng ta bắt đầu với việc chỉ định Image cơ sở của chúng ta. Sử dụng từ khóa FROM để làm điều đó:

FROM python:3

Bước tiếp theo thường là viết các lệnh sao chép các file và cài đặt các phụ thuộc. Đầu tiên, chúng ta thiết lập một thư mục làm việc và sau đó sao chép tất cả các file cho ứng dụng của chúng ta.


# set a directory for the app
WORKDIR /usr/src/app

# copy all the files to the container
COPY . .

Bây giờ, chúng ta đã có các file, chúng ta có thể cài đặt các phụ thuộc.


# install dependencies
RUN pip install --no-cache-dir -r requirements.txt

Bước tiếp theo chúng ta cần xác định là những cổng cần được đưa ra. Vì ứng dụng bình của chúng ta đang chạy trên cổng 5000, đó là những gì chúng ta sẽ chỉ ra.

EXPOSE 5000

Bước cuối cùng là viết lệnh để chạy ứng dụng, đơn giản là - python ./app.py. Chúng ta sử dụng lệnh CMD để làm điều đó

CMD ["python", "./app.py"]

Mục đích chính của CMD là báo cho container biết lệnh nào sẽ chạy khi nó được khởi động. Như vậy là file Dockerfile của chúng ta đã sẵn sàng. Nó sẽ trông như thế này:


FROM python:3

# set a directory for the app
WORKDIR /usr/src/app

# copy all the files to the container
COPY . .

# install dependencies
RUN pip install --no-cache-dir -r requirements.txt

# define the port number the container should expose
EXPOSE 5000

# run the command
CMD ["python", "./app.py"]

Sau khi có file Dockerfile chúng ta đã có thể build Image của chúng mình. Lệnh docker build sẽ tạo ra một Docker Image từ một file Dockerfile.

Phần bên dưới cho bạn thấy kết quả đầu ra khi chạy lệnh docker build. Trước khi bạn tự chạy lệnh, hãy đảm bảo rằng bạn đã thay thế tên người dùng của tôi bằng tên của bạn.

Tên người dùng này phải giống với tên bạn đã tạo khi đăng ký trên Docker Hub. Nếu bạn chưa làm điều đó, xin vui lòng tạo một tài khoản trước khi tiếp tục.

Lệnh docker build khá là đơn giản - nó yêu cầu một tên thẻ tùy chọn là -t và vị trí của thư mục chứa Dockerfile.


$ docker build -t yourusername/catnip .
Sending build context to Docker daemon 8.704 kB
Step 1 : FROM python:3
# Executing 3 build triggers...
Step 1 : COPY requirements.txt /usr/src/app/
 ---> Using cache
Step 1 : RUN pip install --no-cache-dir -r requirements.txt
 ---> Using cache
Step 1 : COPY . /usr/src/app
 ---> 1d61f639ef9e
Removing intermediate container 4de6ddf5528c
Step 2 : EXPOSE 5000
 ---> Running in 12cfcf6d67ee
 ---> f423c2f179d1
Removing intermediate container 12cfcf6d67ee
Step 3 : CMD python ./app.py
 ---> Running in f01401a5ace9
 ---> 13e87ed1fbc2
Removing intermediate container f01401a5ace9
Successfully built 13e87ed1fbc2

Nếu bạn không có Image python:3, đầu tiên Docker Client sẽ kéo Image này về và sau đó tạo Image của bạn.

Do đó, kết quả đầu ra của bạn từ việc chạy lệnh sẽ trông khác với của tôi. Nếu mọi thứ diễn ra tốt đẹp, Image của bạn đã sẵn sàng!

Chạy lệnh docker images và xem Image của bạn có hiển thị trong danh sách không.

Bước cuối cùng trong phần này là chạy Image và xem nó có thực sự hoạt động không (thay thế tên người dùng của tôi bằng tên của bạn).


$ docker run -p 8888:5000 yourusername/catnip
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

Lệnh chúng tôi vừa chạy cổng 5000 đã sử dụng cho máy chủ bên trong container và hiển thị bên ngoài này trên cổng 8888. Truy cập URL với cổng 8888, nơi ứng dụng của bạn sẽ hoạt động.

Chạy ứng dụng flask trong Docker container

Xin chúc mừng! Bạn đã tạo thành công Image docker đầu tiên của bạn.

Docker trên AWS

Ứng dụng tuyệt vời thì không thể không chia sẻ với bạn bè, phải không nào? Vì vậy, trong phần này chúng ta sẽ xem làm thế nào chúng ta có thể triển khai ứng dụng tuyệt vời của mình lên đám mây để chúng ta có thể chia sẻ nó với bạn bè!

Chúng tôi sẽ sử dụng AWS Elastic Beanstalk để khởi động và chạy ứng dụng của chúng tôi trong một vài cú nhấp chuột. Chúng ta cũng sẽ thấy việc ứng dụng của chúng ta có thể mở rộng và quản lý dễ dàng như thế nào với Beanstalk!

Docker Push

Điều đầu tiên mà chúng ta cần làm trước khi chúng ta triển khai ứng dụng của mình lên AWS là xuất bản Image của chúng ta lên một sổ đăng ký mà AWS có thể truy cập.

Có rất nhiều sổ đăng ký Docker khác nhau mà bạn có thể sử dụng (thậm chí bạn có thể lưu trữ riêng cho bạn). Hiện tại, hãy sử dụng Docker Hub để xuất bản Image.

Nếu đây là lần đầu tiên bạn đẩy một Image, Docker Client sẽ yêu cầu bạn đăng nhập. Cung cấp cùng thông tin đăng nhập mà bạn đã sử dụng để đăng nhập vào Docker Hub.


$ docker login
Login in with your Docker ID to push and pull images from Docker Hub. If you do not have a Docker ID, head over to https://hub.docker.com to create one.
Username: yourusername
Password:
WARNING! Your password will be stored unencrypted in /Users/yourusername/.docker/config.json
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/credential-store

Login Succeeded

Để xuất bản, chỉ cần gõ lệnh bên dưới và đừng quên thay thế tên của Image ở trên bằng tên của bạn. Điều quan trọng là nó phải có định dạng yourusername/image_name để Client biết nơi xuất bản.


$ docker push yourusername/catnip

Khi đã xong, bạn có thể xem Image của mình trên Docker Hub. Ví dụ, đây là trang web cho Image của tôi.

Lưu ý: Một điều mà tôi muốn làm rõ trước khi chúng ta tiếp tục là không bắt buộc phải lưu trữ Image của bạn trên sổ đăng ký công khai (hoặc bất kỳ sổ đăng ký nào) để triển khai lên AWS. Trong trường hợp bạn đang viết mã cho startup kỳ lân triệu đô tiếp theo, bạn hoàn toàn có thể bỏ qua bước này. Lý do tại sao chúng tôi đẩy Image của mình một cách công khai là vì nó giúp triển khai cực kỳ đơn giản bằng cách bỏ qua một vài bước cấu hình trung gian.

Bây giờ Image của bạn đang trực tuyến, bất kỳ ai đã cài đặt docker đều có thể chơi với ứng dụng của bạn bằng cách chạy lệnh sau:


$ docker run -p 8888:5000 yourusername/catnip

Nếu bạn đã đã từng vò đầu bứt tóc khi thiết lập cấu hình ứng dụng / chia sẻ cấu hình ứng dụng cục bộ trong quá khứ, bạn sẽ biết rất rõ điều này tuyệt vời như thế nào. Đó là lý do Docker rất tuyệt!

Beanstalk

AWS Elastic Beanstalk (EB) là một PaaS (Nền tảng là một Dịch vụ) được cung cấp bởi AWS. Nếu bạn đã sử dụng Heroku, Google App Engine, v.v. bạn sẽ cảm thấy như ở nhà.

Là một nhà phát triển, bạn chỉ cần nói với EB cách chạy ứng dụng của bạn và nó sẽ lo phần còn lại - bao gồm mở rộng quy mô, giám sát và thậm chí cập nhật.

Vào tháng 4 năm 2014, EB đã thêm hỗ trợ để chạy các triển khai một container Docker, đây là những gì chúng tôi sẽ sử dụng để triển khai ứng dụng của mình.

Mặc dù EB có CLI rất trực quan , nhưng nó yêu cầu một số thiết lập và để đơn giản hóa, chúng tôi sẽ sử dụng giao diện người dùng web để khởi chạy ứng dụng của chúng tôi.

Để làm theo, bạn cần có một tài khoản AWS đang hoạt động. Nếu bạn chưa có, vui lòng làm điều đó ngay bây giờ trước khi tiếp tục - bạn sẽ cần nhập thông tin thẻ tín dụng của mình.

Nhưng đừng lo lắng, nó miễn phí và bất cứ điều gì chúng tôi làm trong hướng dẫn này cũng sẽ miễn phí! Bắt đầu nào.

Dưới đây là các bước:

  • Đăng nhập vào bảng điều khiển AWS của bạn .
  • Nhấp chuột vào Elastic Beanstalk. Nó sẽ nằm trong phần tính toán ở phía trên bên trái. Ngoài ra, bạn có thể truy cập bằng Elastic Beanstalk console.
Elastic Beanstalk
  • Nhấp vào "Create New Application" ở trên cùng bên phải
  • Đặt cho ứng dụng của bạn một tên dễ nhớ (nhưng duy nhất) và cung cấp mô tả (tùy chọn)
  • Trong màn hình New Environment, tạo môi trường mới và chọn Web Server Environment.
  • Điền thông tin môi trường bằng cách chọn một tên miền. URL này là những gì bạn sẽ chia sẻ với bạn bè của mình vì vậy hãy đảm bảo là nó dễ nhớ.
  • Trong phần cấu hình cơ sở. Chọn Docker từ predefined platform.
Elastic Beanstalk
  • Bây giờ chúng ta cần tải lên mã ứng dụng của chúng ta. Nhưng vì ứng dụng của chúng ta được đóng gói trong một Docker container, chúng ta chỉ cần nói với EB về container của chúng ta. Mở file Dockerrun.aws.json nằm trong thư mục flask-app và chỉnh sửa Name của Image thành tên Image của bạn. Đừng lo lắng, tôi sẽ giải thích nội dung của tập tin ngay. Khi bạn đã hoàn tất, nhấp vào nút radio cho "Upload your Code", chọn file này và nhấp vào "Upload".
  • Bây giờ bấm vào "Create environment". Màn hình cuối cùng mà bạn nhìn thấy sẽ có một vài spinner cho biết môi trường của bạn đang được thiết lập. Nó thường mất khoảng 5 phút để thiết lập lần đầu tiên.

Trong khi chờ đợi, chúng ta sẽ xem file Dockerrun.aws.json chứa những gì. File này về cơ bản là một file AWS chỉ định để nói với EB về cấu hình ứng dụng và docker của chúng ta.


{
  "AWSEBDockerrunVersion": "1",
  "Image": {
    "Name": "prakhar1989/catnip",
    "Update": "true"
  },
  "Ports": [
    {
      "ContainerPort": 5000,
      "HostPort": 8000
    }
  ],
  "Logging": "/var/log/nginx"
}

Nội dung file đã tự giải thích tuy nhiên bạn luôn có thể tham khảo tài liệu chính thức để biết thêm thông tin. Chúng ta cung cấp tên của Image mà EB sử dụng cùng với một cổng mà container sẽ mở.

Hy vọng đến lúc này thì ví dụ của chúng ta đã sẵn sàng. Đến trang EB và bạn sẽ thấy một dấu tick màu xanh cho biết ứng dụng của bạn đang hoạt động.

Elastic Beanstalk

Bây giờ hãy mở URL trong trình duyệt của bạn và bạn sẽ thấy ứng dụng. Giờ thì gửi liên kết này đến bạn bè và gia đình của bạn để họ cũng có thể thưởng thức những chú mèo dễ thương.

Dọn dẹp

Khi bạn đã hoàn thành việc đưa ứng dụng của mình lên AWS, hãy nhớ dừng môi trường để bạn không bị tính phí cho các tài nguyên bổ sung.

Elastic Beanstalk

Xin chúc mừng! Bạn đã triển khai thành công ứng dụng Docker đầu tiên của mình lên đám mây!

Có vẻ nhiều bước, nhưng với công cụ dòng lệnh cho EB, bạn gần như có thể bắt chước chức năng của Heroku trong một vài lần nhấn phím!

Hy vọng rằng, bạn đồng ý rằng Docker sẽ giảm bớt rất nhiều khó khăn trong việc xây dựng và triển khai các ứng dụng trên đám mây.

Trong phần tiếp theo (và cuối cùng) của hướng dẫn, chúng ta sẽ nâng cao kiến ​​thức một chút và triển khai một ứng dụng mô phỏng thế giới thực chặt chẽ hơn; một ứng dụng với tầng back-end lưu trữ dữ liệu.

MÔI TRƯỜNG NHIỀU CONTAINER

Trong phần trước, chúng ta đã thấy việc chạy các ứng dụng với Docker dễ dàng và thú vị như thế nào.

Chúng ta bắt đầu với một trang web tĩnh đơn giản và sau đó thử một ứng dụng Flask. Cả hai có thể chạy cục bộ và trên đám mây chỉ bằng một vài lệnh.

Một điểm chung của cả hai ứng dụng này là chúng đang chạy trong một container.

Những người bạn có kinh nghiệm chạy các dịch vụ trong môi trường production đều biết rằng các ứng dụng ngày nay không đơn giản như vậy.

Hầu như luôn luôn có một cơ sở dữ liệu (hoặc bất kỳ loại lưu trữ lâu dài nào khác) liên quan.

Các hệ thống như RedisMemcached đã trở thành một phần không thể thiếu của hầu hết các kiến ​​trúc ứng dụng web.

Do đó, trong phần này, chúng ta sẽ dành thời gian học cách Dockerize các ứng dụng dựa trên các dịch vụ khác nhau để chạy.

Cụ thể, chúng ta sẽ xem làm thế nào để có thể chạy và quản lý môi trường docker nhiều container.

Tại sao lại cần nhiều container? Chà, một trong những điểm chính của Docker là cách nó cung cấp sự cô lập. Ý tưởng kết hợp một tiến trình với các phụ thuộc của nó trong container là điều làm cho nó trở nên mạnh mẽ.

Đó là một chiến lược tốt để tách các tầng ứng dụng của bạn, nên giữ các container cho mỗi dịch vụ riêng biệt. Mỗi tầng có thể có nhu cầu tài nguyên khác nhau và những nhu cầu đó có thể tăng với tốc độ khác nhau.

Bằng cách tách các tầng thành các container khác nhau, chúng ta có thể kết hợp các tầng bằng cách sử dụng kiểu thể hiện phù hợp nhất dựa trên nhu cầu tài nguyên khác nhau.

Điều này cũng rất phù hợp với kiến trúc microservice, một trong những lý do chính khiến Docker (hoặc bất kỳ công nghệ container nào khác) đi đầu trong các kiến ​​trúc microservice hiện đại.

SF Food Trucks

Ứng dụng mà chúng ta sẽ Dockerize được gọi là SF Food Trucks. Mục tiêu của tôi khi xây dựng ứng dụng này là có một cái gì đó hữu ích (trong đó giống với ứng dụng trong thế giới thực), dựa vào ít nhất một dịch vụ, nhưng không quá phức tạp cho mục đích của hướng dẫn này. Đây là những gì tôi đã đưa ra.

Food Trucks

Phần cuối của ứng dụng được viết bằng Python (Flask) và để tìm kiếm, nó sử dụng Elaticsearch.

Giống như mọi thứ khác trong hướng dẫn này, toàn bộ nguồn có sẵn trên Github. Chúng tôi sẽ sử dụng ứng dụng này để tìm hiểu cách xây dựng, chạy và triển khai môi trường nhiều container.

Trước tiên, hãy sao chép dự án về máy tính của bạn.


$ git clone https://github.com/prakhar1989/FoodTrucks
$ cd FoodTrucks
$ tree -L 2
.
├── Dockerfile
├── README.md
├── aws-compose.yml
├── docker-compose.yml
├── flask-app
│   ├── app.py
│   ├── package-lock.json
│   ├── package.json
│   ├── requirements.txt
│   ├── static
│   ├── templates
│   └── webpack.config.js
├── setup-aws-ecs.sh
├── setup-docker.sh
├── shot.png
└── utils
    ├── generate_geojson.py
    └── trucks.geojson

Thư mục flask-app chứa các ứng dụng Python, trong khi thư mục utils có một số tiện ích để nạp dữ liệu vào Elasticsearch.

Thư mục cũng chứa một số file YAML và Dockerfile, tất cả chúng sẽ được trình bày chi tiết trong hướng dẫn này.

Chúng ta có thể thấy rằng ứng dụng này bao gồm một backend là Flask và dịch vụ Elaticsearch. Do đó chúng ta sẽ tạo hai container cho ứng dụng này - một container chạy Flask và một container khác chạy dịch vụ Elaticsearch (ES).

Bằng cách đó, nếu ứng dụng của chúng ta trở nên phổ biến, chúng ta có thể mở rộng quy mô bằng cách thêm nhiều container tùy thuộc vào vị trí nút cổ chai.

Chúng ta đã xây dựng container riêng của chúng ta trong phần trước. Đối với Elaticsearch, hãy xem liệu chúng ta có thể tìm thấy thứ gì đó trên Docker Hub không.


$ docker search elasticsearch
NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
elasticsearch                     Elasticsearch is a powerful open source se...   697       [OK]
itzg/elasticsearch                Provides an easily configurable Elasticsea...   17                   [OK]
tutum/elasticsearch               Elasticsearch image - listens in port 9200.     15                   [OK]
barnybug/elasticsearch            Latest Elasticsearch 1.7.2 and previous re...   15                   [OK]
digitalwonderland/elasticsearch   Latest Elasticsearch with Marvel & Kibana       12                   [OK]
monsantoco/elasticsearch          ElasticSearch Docker image                      9                    [OK]

Khá ngạc nhiên, có một Image được hỗ trợ chính thức cho Elaticsearch. Để chạy ES, chúng ta chỉ cần sử dụng lệnh docker run và có một container ES có một node chạy cục bộ.

Lưu ý: Elastic, công ty đứng sau Elaticsearch, duy trì đăng ký riêng cho các sản phẩm Elastic. Bạn nên sử dụng các Image từ sổ đăng ký đó nếu bạn có kế hoạch sử dụng Elaticsearch.

Trước tiên hãy kéo Image về máy tính của bạn:


$ docker pull docker.elastic.co/elasticsearch/elasticsearch:6.3.2

Sau đó chạy nó trong chế độ development bằng cách chỉ định các cổng và thiết lập biến môi trường để cấu hình cụm Elaticsearch chạy dưới dạng một node.


$ docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.3.2
277451c15ec183dd939e80298ea4bcf55050328a39b04124b387d668e3ed3943
Lưu ý: Nếu container của bạn gặp vấn đề về bộ nhớ, bạn có thể cần phải điều chỉnh một số cờ JVM để hạn chế mức tiêu thụ bộ nhớ của nó.

Như đã thấy ở trên, chúng tôi sử dụng --name es để thiết lập cho container của chúng ta một tên giúp dễ sử dụng trong các lệnh tiếp theo.

Khi container được khởi động, chúng ta có thể thấy các bản ghi bằng cách chạy docker container logs với tên container (hoặc ID) để kiểm tra các bản ghi. Bạn sẽ thấy các bản ghi tương tự như bên dưới nếu Elaticsearch bắt đầu thành công.

Lưu ý: Elaticsearch mất vài giây để bắt đầu, do đó bạn có thể phải đợi trước khi bạn nhìn thấy initialized trong log.

$ docker container ls
CONTAINER ID        IMAGE                                                 COMMAND                  CREATED             STATUS              PORTS                                            NAMES
277451c15ec1        docker.elastic.co/elasticsearch/elasticsearch:6.3.2   "/usr/local/bin/dock…"   2 minutes ago       Up 2 minutes        0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp   es

$ docker container logs es
[2018-07-29T05:49:09,304][INFO ][o.e.n.Node               ] [] initializing ...
[2018-07-29T05:49:09,385][INFO ][o.e.e.NodeEnvironment    ] [L1VMyzt] using [1] data paths, mounts [[/ (overlay)]], net usable_space [54.1gb], net total_space [62.7gb], types [overlay]
[2018-07-29T05:49:09,385][INFO ][o.e.e.NodeEnvironment    ] [L1VMyzt] heap size [990.7mb], compressed ordinary object pointers [true]
[2018-07-29T05:49:11,979][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded module [x-pack-security]
[2018-07-29T05:49:11,980][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded module [x-pack-sql]
[2018-07-29T05:49:11,980][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded module [x-pack-upgrade]
[2018-07-29T05:49:11,980][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded module [x-pack-watcher]
[2018-07-29T05:49:11,981][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded plugin [ingest-geoip]
[2018-07-29T05:49:11,981][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded plugin [ingest-user-agent]
[2018-07-29T05:49:17,659][INFO ][o.e.d.DiscoveryModule    ] [L1VMyzt] using discovery type [single-node]
[2018-07-29T05:49:18,962][INFO ][o.e.n.Node               ] [L1VMyzt] initialized
[2018-07-29T05:49:18,963][INFO ][o.e.n.Node               ] [L1VMyzt] starting ...
[2018-07-29T05:49:19,218][INFO ][o.e.t.TransportService   ] [L1VMyzt] publish_address {172.17.0.2:9300}, bound_addresses {0.0.0.0:9300}
[2018-07-29T05:49:19,302][INFO ][o.e.x.s.t.n.SecurityNetty4HttpServerTransport] [L1VMyzt] publish_address {172.17.0.2:9200}, bound_addresses {0.0.0.0:9200}
[2018-07-29T05:49:19,303][INFO ][o.e.n.Node               ] [L1VMyzt] started
[2018-07-29T05:49:19,439][WARN ][o.e.x.s.a.s.m.NativeRoleMappingStore] [L1VMyzt] Failed to clear cache for realms [[]]
[2018-07-29T05:49:19,542][INFO ][o.e.g.GatewayService     ] [L1VMyzt] recovered [0] indices into cluster_state

Bây giờ, hãy thử xem liệu có thể gửi yêu cầu đến container Elaticsearch không. Chúng tôi sử dụng cổng 9200 để gửi yêu cầu cURL đến container.


$ curl 0.0.0.0:9200
{
  "name" : "ijJDAOm",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "a_nSV3XmTCqpzYYzb-LhNw",
  "version" : {
    "number" : "6.3.2",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "053779d",
    "build_date" : "2018-07-20T05:20:23.451332Z",
    "build_snapshot" : false,
    "lucene_version" : "7.3.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

Tuyệt vời! Như vậy là container Elasticsearch đã chạy.

Trong ứng dụng của chúng ta, ngoài việc cài đặt các phụ thuộc Python thông qua pip, chúng tôi muốn file Javascript được rút gọn khi xuất bản lên môi trường production.

Chúng tôi sẽ cần Nodejs để thực hiện điều này. Vì vậy chúng tôi sẽ thực hiện vài chỉnh sửa bắt đầu từ Image ubuntu cơ sở để xây dựng Dockerfile từ đầu.

Lưu ý: nếu bạn thấy rằng Image hiện tại không đáp ứng nhu cầu của bạn, hãy bắt đầu từ một Image cơ sở khác và tự điều chỉnh nó. Đối với hầu hết các Image trên Docker Hub, bạn có thể tìm thấy Dockerfile tương ứng trên Github. Đọc qua Dockerfile là một trong những cách tốt nhất để tìm ra cách viết của riêng bạn.

Dockerfile của chúng tôi cho ứng dụng Flask trông như dưới đây:


# start from base
FROM ubuntu:latest

MAINTAINER Prakhar Srivastav <prakhar@prakhar.me>

# install system-wide deps for python and node
RUN apt-get -yqq update
RUN apt-get -yqq install python-pip python-dev curl gnupg
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
RUN apt-get install -yq nodejs

# copy our application code
ADD flask-app /opt/flask-app
WORKDIR /opt/flask-app

# fetch app specific deps
RUN npm install
RUN npm run build
RUN pip install -r requirements.txt

# expose port
EXPOSE 5000

# start app
CMD [ "python", "./app.py" ]

Có một vài thay đổi trong file Dockerfile mới này. Chúng tôi bắt đầu với Image cơ sở Ubuntu LTS và sử dụng trình quản lý gói apt-get để cài đặt các phụ thuộc là Python và Nodejs. Cờ yqq được sử dụng để bỏ qua các cảnh báo.

Sau đó, chúng tôi sử dụng lệnh ADD để sao chép ứng dụng của mình vào một ổ đĩa mới trong container - /opt/flask-app.

Đây là nơi mã của chúng tôi sẽ cư trú. Chúng tôi cũng thiết lập đây là thư mục làm việc của chúng tôi để các lệnh sau sẽ được chạy trong ngữ cảnh của vị trí này.

Bây giờ, các phụ thuộc trên toàn hệ thống đã được cài đặt, chúng tôi có thể cài đặt các ứng dụng dành riêng cho ứng dụng flask.

Trước hết, chúng tôi giải quyết Nodejs bằng cách cài đặt các gói từ npm và chạy lệnh build như được định nghĩa trong file package.json của chúng tôi.

Chúng tôi hoàn thành việc cài đặt các gói Python, mở cổng và chỉ định CMD để chạy như chúng tôi đã làm trong phần trước.

Cuối cùng, chúng ta build Image và chạy container (thay thế prakhar1989 bằng tên người dùng của bạn bên dưới).


$ docker build -t prakhar1989/foodtrucks-web .

Trong lần chạy đầu tiên, điều này sẽ mất một chút thời gian vì Docker Client sẽ tải xuống image ubuntu, chạy tất cả các lệnh và chuẩn bị cho image của bạn.

Chạy lại lệnh docker build sau bất kỳ thay đổi tiếp theo nào bạn thực hiện đối với mã ứng dụng sẽ gần như là tức thời. Bây giờ hãy thử chạy ứng dụng của chúng tôi.


$ docker run -P --rm prakhar1989/foodtrucks-web
Unable to connect to ES. Retying in 5 secs...
Unable to connect to ES. Retying in 5 secs...
Unable to connect to ES. Retying in 5 secs...
Out of retries. Bailing out...

Ồ không! Ứng dụng flask của chúng tôi không thể chạy được vì nó không thể kết nối với Elaticsearch.

Làm thế nào để chúng ta nói với một container về container khác và khiến chúng giao tiếp với nhau? Câu trả lời nằm ở phần tiếp theo.



Bài viết liên quan:

Giới thiệu về Docker - một trong những dịch vụ hot nhất hiện nay.