Cách định dạng môi trường thử nghiệm Continuous Integration với Docker và Docker Compose trên Ubuntu 14.04

4 năm trước

Một bài viết từ Docker

Giới thiệu

Continuous integration (CI) đề cập đến thực tế nơi người khai triển tích hợp mã càng thường xuyên càng tốt và mọi cam kết được kiểm tra trước và sau khi được hợp nhất vào một kho lưu trữ được chia sẻ bởi một bản dựng tự động.

CI tăng tốc quá trình phát triển và giảm thiểu rủi ro của các vấn đề quan trọng trong sản xuất, nhưng không tầm thường khi thiết lập; các bản dựng tự động chạy trong một môi trường khác nơi cài đặt runtime dependencies và cấu hình của các dịch vụ bên ngoài có thể khác với môi trường cục bộ và dev của bạn.

Docker là một nền tảng container nhằm đơn giản các vấn đề tiêu chuẩn hóa môi trường để việc triển khai các ứng dụng có thể được chuẩn hóa (tìm hiểu thêm về Docker). Đối với các nhà phát triển, Docker cho phép mô phỏng các môi trường sản xuất trên các máy cục bộ bằng cách chạy các thành phần ứng dụng trong các container cục bộ. Các container này có thể dễ dàng tự động hóa bằng cách sử dụng Docker Compose, độc lập với ứng dụng và nền tảng OS.

Hướng dẫn này sử dụng Docker Compose để trình bày sự tự động hóa của quy trình công việc CI.

Chúng ta sẽ tạo ứng dụng Python Dockerized "Hello world" và tập lệnh thử nghiệm Bash. Ứng dụng Python yêu cầu hai container để chạy: một cho chính ứng dụng và một Redis container cho bộ nhớ được yêu cầu phụ thuộc vào ứng dụng.

Sau đó, tập lệnh thử nghiệm sẽ được Dockerized trong container riêng và toàn bộ môi trường thử nghiệm được chuyển đến tệp docker-compose.test.yml để có thể đảm bảo rằng đang chạy mọi thử nghiệm trên môi trường ứng dụng mới và thống nhất.

Cách tiếp cận này cho thấy có thể xây dựng môi trường thử nghiệm mới, giống hệt nhau cho ứng dụng của bạn, bao gồm cả các phụ thuộc, mỗi khi bạn kiểm tra nó.

Do đó, chúng ta tự động hóa quy trình công việc CI một cách độc lập với ứng dụng đang được thử nghiệm và cơ sở hạ tầng cơ bản.

 

Yêu cầu

Trước khi bắt đầu, bạn cần:

  • Máy chủ Ubuntu 14.04 

  • Người dùng non-root với quyền sudo

  • Một số quen thuộc với Docker và Docker Compose; các liên kết là để tham khảo, vì chúng ta sẽ cài đặt phần mềm trong hướng dẫn này

  • Thử nghiệm, thử nghiệm và nhiều thử nghiệm (tự động) khác! Bạn cần phải được hiểu về những lợi thế của việc thử nghiệm và áp dụng CI cho quy trình phát triển

 

Bước 1 - Cài đặt Docker

Nếu Docker chưa có trên máy chủ của bạn, cách dễ nhất là tải xuống và thực hiện tập lệnh cài đặt Docker chính thức, sẽ nhắc nhập mật khẩu sudo 

wget -qO- https://get.docker.com/ | sh 

Để làm việc với Docker dễ dàng hơn, hãy thêm người dùng của bạn vào nhóm docker bằng lệnh sau:

sudo usermod -aG docker $(whoami) 

Đăng xuất và sau đó đăng nhập vào máy chủ để kích hoạt nhóm docker cho người dùng của bạn.

 

Bước 2 - Cài đặt Docker Compose

Docker Compose là một công cụ mã nguồn mở để xác định và chạy các ứng dụng đa container bằng cách sử dụng cách tiếp cận khai báo. Để cài đặt Docker Compose, hãy thực hiện các lệnh sau:

sudo apt-get update 
sudo apt-get -y install python-pip 
sudo pip install docker-compose 

Xác minh rằng docker-compose được cài đặt đúng bằng cách thực hiện:

docker-compose --version 

Bạn sẽ thấy một điều gì đó như:

Output
docker-compose version 1.6.2, build 4d72027

Điều này cho biết phiên bản docker-compose bạn cài đặt.

Bước 3 - Tạo ứng dụng Python "Hello World"

Trong bước này, chúng ta sẽ tạo ứng dụng Python đơn giản qua ví dụ về loại ứng dụng bạn có thể kiểm tra với thiết lập này.

Tạo thư mục mới cho ứng dụng bằng cách thực hiện:

cd ~ 
mkdir hello_world 
cd hello_world 

Chỉnh sửa tập mới app.py với nano:

nano app.py 

Thêm nội dung như sau:

app.py
from flask import Flask
from redis import Redis
app = Flask(__name__)
redis = Redis(host="redis")
@app.route("/")
def hello():
visits = redis.incr('counter')
html = "

Hello World!

" \ "Visits: {visits}" \ "
" return html.format(visits=visits) if __name__ == "__main__": app.run(host="0.0.0.0", port=80)

app.py là ứng dụng web dựa trên Flask kết nối với dịch vụ dữ liệu Redisis. Dòng visits = redis.incr('counter') tăng số lượt truy cập và vẫn tồn tại giá trị này trong Redis. Cuối cùng, một thông điệp Hello World với số lượt truy cập trở về trong HTML.

Ứng dụng có hai phụ thuộc, Flask Redis, có thể thấy trong hai dòng đầu tiên. Những phụ thuộc này phải được xác định trước khi thực thi ứng dụng. Chỉnh sửa tệp mới:

nano requirements.txt 

Thêm nội dung:

requirements.txt
Flask
Redis
 

Bước 4 - Dockerize ứng dụng "Hello World"

Docker sử dụng tập tin gọi là Dockerfile chỉ ra các bước cần thiết để xây dựng hình ảnh Docker cho một ứng dụng cụ thể. Chỉnh sửa tệp mới:

nano Dockerfile 

Thêm nội dung như sau:

Dockerfile
FROM python:2.7
WORKDIR /app
ADD requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt
ADD app.py /app/app.py
EXPOSE 80
CMD ["python", "app.py"]

Hãy phân tích ý nghĩa của mỗi dòng:

  • FROM python:2.7: cho biết hình ảnh ứng dụng "Hello World" được xây dựng từ hình ảnh Docker python:2.7  chính thức
  • WORKDIR /app: đặt thư mục làm việc bên trong hình ảnh Docker vào /app
  • ADD requirements.txt /app/requirements.txt: thêm tệp requirements.txt vào hình ảnh Docker
  • RUN pip install -r requirements.txt: cài đặt các phụ thuộc ứng dụng pip 
  • ADD app.py /app/app.py: thêm mã nguồn ứng dụng vào hình ảnh Docker
  • EXPOSE 80: cho biết rằng ứng dụng có thể thực hiện tại cổng 80 (cổng web công cộng chuẩn)
  • CMD ["python", "app.py"]: lệnh khởi động ứng dụng

Tệp Dockerfile này có tất cả thông tin cần thiết để xây dựng thành phần chính của ứng dụng "Hello World".

Các phụ thuộc

Bây giờ chúng ta sẽ đến phần phức tạp hơn của ví dụ. Ứng dụng yêu cầu Redis như một dịch vụ bên ngoài. Đây là loại phụ thuộc khó thiết lập theo cách giống hệt nhau trong môi trường Linux truyền thống, nhưng với Docker Compose, chúng ta có thể thiết lập nó theo một cách lặp lại mỗi lần.

Hãy tạo tệp docker-compose.yml để bắt đầu sử dụng Docker Compose.

Chỉnh sửa tệp mới:

nano docker-compose.yml 

Thêm nội dung như sau:

docker-compose.yml
web:
build: .
dockerfile: Dockerfile
links:
- redis
ports:
- "80:80"
redis:
image: redis

Tập tin Docker Compose cho biết cách quay tròn ứng dụng "Hello World" cục bộ trong hai Docker container

Nó định nghĩa hai container, web và redis.

  • web sử dụng thư mục hiện tại cho bối cảnh build, và xây dựng ứng dụng Python từ tệp  Dockerfile vừa tạo. Đây là hình ảnh Docker cục bộ được tạo cho ứng dụng Python. Nó định nghĩa một liên kết đến redis container để có quyền truy cập vào redis container IP và làm cho cổng 80 có thể truy cập công khai từ Internet bằng cách sử dụng IP công cộng của máy chủ Ubuntu của bạn

  • redis được thực hiện từ một hình ảnh Docker công cộng chuẩn, có tên là redis

 

Bước 5 - Triển khai ứng dụng "Hello World"

Trong bước này, chúng ta sẽ triển khai ứng dụng và cuối cùng nó sẽ có thể truy cập được qua Internet. Với mục đích của quy trình triển khai, bạn có thể xem đây là môi trường sản xuất, phát triển hoặc dàn dựng, vì bạn có thể triển khai ứng dụng theo cùng một cách nhiều lần.

Tệp docker-compose.yml và Dockerfile cho phép bạn tự động hóa việc triển khai các môi trường cục bộ bằng cách thực hiện:

docker-compose -f ~/hello_world/docker-compose.yml build 
docker-compose -f ~/hello_world/docker-compose.yml up -d 

Dòng đầu tiên xây dựng hình ảnh ứng dụng cục bộ từ tệp Dockerfile. Dòng thứ hai chạy web và redis  container trong chế độ daemon (-d),như được chỉ định trong tệp docker-compose.yml.

Kiểm tra rằng các container ứng dụng đã được tạo bằng cách thực thi:

docker ps 

Điều này sẽ hiển thị hai container đang chạy, là helloworld_web_1 và helloworld_redis_1.

Hãy kiểm tra xem ứng dụng có đang hoạt động không. Chúng ta có thể lấy IP của helloworld_web_1  container bằng cách thực hiện:

WEB_APP_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' helloworld_web_1) 
echo $WEB_APP_IP 

Kiểm tra xem ứng dụng web có trả lại thông điệp thích hợp không:

curl http://${WEB_APP_IP}:80 

Điều này sẽ trả về một điều gì đó như:

Output
 

Hello World!

 

Visits: 1

 

Số lượt truy cập tăng lên mỗi khi nhấn điểm cuối này. Bạn cũng có thể truy cập ứng dụng "Hello World" từ trình duyệt của mình bằng cách truy cập địa chỉ IP công cộng của máy chủ Ubuntu.

Cách tùy chỉnh cho ứng dụng riêng của bạn

Chìa khóa để thiết lập ứng dụng của riêng bạn là đưa ứng dụng vào Docker container và chạy từng phụ thuộc từ container của chính ứng dụng đó. Sau đó, bạn có thể xác định mối quan hệ giữa các container với Docker Compose, như được minh họa trong ví dụ.

 

Bước 6 - Tạo tập lệnh thử nghiệm

Bây giờ chúng ta sẽ tạo tập lệnh thử nghiệm cho ứng dụng Python. Đây là tập lệnh đơn giản để kiểm tra đầu ra HTTP của ứng dụng. Tập lệnh là một ví dụ về loại thử nghiệm mà bạn muốn chạy như là một phần của quá trình triển khai.

Chỉnh sửa tệp mới:

nano test.sh 

Thêm nội dung như sau:

test.sh
sleep 5
if curl web | grep -q 'Visits: '; then
echo "Tests passed!"
exit 0
else
echo "Tests failed!"
exit 1
fi

test.sh kiểm tra kết nối web cơ bản của ứng dụng "Hello World". Nó sử dụng cURL để lấy lại số lượt truy cập và báo cáo về việc thử nghiệm có được thông qua hay không.

 

Bước 7 - Tạo môi trường thử nghiệm

Để thử nghiệm ứng dụng, cần triển khai một môi trường thử nghiệm. Chúng ta muốn đảm bảo nó giống với môi trường ứng dụng trực tiếp đã tạo ở Bước 5.

Đầu tiên, chúng ta cần Dockerize tập lệnh thử nghiệm bằng cách tạo một tệp Dockerfile mới. Chỉnh sửa tệp mới:

nano Dockerfile.test 

Thêm nội dung như sau:

Dockerfile.test
FROM ubuntu:trusty
RUN apt-get update && apt-get install -yq curl && apt-get clean
WORKDIR /app
ADD test.sh /app/test.sh
CMD ["bash", "test.sh"]

Dockerfile.test mở rộng hình ảnh ubuntu:trusty chính thức để cài đặt phụ thuộc curl , thêm tests.sh vào hệ thống tệp tin hình ảnh, và chỉ ra lệnh CMD thực thi tập lệnh thử nghiệm với Bash.

Sau khi các thử nghiệm là Dockerized, chúng có thể được thực hiện theo một cách có thể sao chép và không thể biết.

Bước tiếp theo là liên kết container thử nghiệm với ứng dụng "Hello World". Đây là nơi Docker Compose đến giải cứu một lần nữa. Chỉnh sửa tệp mới:

nano docker-compose.test.yml 

Thêm nội dung như sau:

docker-compose.test.yml
sut:
build: .
dockerfile: Dockerfile.test
links:
- web
web:
build: .
dockerfile: Dockerfile
links:
- redis
redis:
image: redis

Phần thứ hai của tập tin Docker Compose triển khai ứng dụng web chính và phụ thuộc redis của nó theo cùng cách với tập tin docker-compose.yml trước đó. Đây là một phần của tệp chỉ định web và  redis  containers. Sự khác biệt duy nhất là web container không còn hiển thị cổng 80, vì vậy ứng dụng không có sẵn trên Internet công cộng trong khi kiểm tra. Vì vậy, có thể thấy rằng chúng ta đang xây dựng ứng dụng và các phụ thuộc giống hệt như cách chúng đang triển khai trực tiếp.

Tệp docker-compose.test.yml cũng định nghĩa sut container (được đặt tên cho hệ thống trong các thử nghiệm) chịu trách nhiệm thực hiện các kiểm tra tích hợp. sut container chỉ định thư mục hiện tại làm thư mục build và chỉ định tệp Dockerfile.test. Nó liên kết với web container để địa chỉ IP của container ứng dụng có thể truy cập vào tập lệnh test.sh.

Cách tùy chỉnh cho ứng dụng riêng của bạn

Lưu ý rằng docker-compose.test.yml bao gồm hàng tá các dịch vụ bên ngoài và nhiều container thử nghiệm. Docker có thể chạy tất cả các phụ thuộc này trên một máy chủ duy nhất vì mỗi container chia sẻ nền tảng OS.

Nếu có nhiều thử nghiệm chạy trên ứng dụng của mình, bạn có thể tạo thêm Dockerfiles cho chúng, tương tự như tệp Dockerfile.test được hiển thị ở trên.

Sau đó, bạn có thể thêm các container bổ sung bên dưới sut container trong tệp docker-compose.test.yml, tham chiếu đến các Dockerfiles bổ sung.

 

Bước 8 - Kiểm tra ứng dụng "Hello World"

Cuối cùng, mở rộng các ý tưởng Docker từ môi trường cục bộ đến môi trường thử nghiệm, chúng ta có thể tự động kiểm tra ứng dụng khi sử dụng Docker bằng cách thực hiện:

docker-compose -f ~/hello_world/docker-compose.test.yml -p ci build 

Lệnh này xây dựng các hình ảnh cục bộ cần thiết bởi docker-compose.test.yml. Lưu ý rằng chúng ta đang sử dụng -f để trỏ đến docker-compose.test.yml và -p để chỉ ra một tên dự án cụ thể.

Bây giờ quay tròn môi trường thử nghiệm mới của bạn bằng cách thực hiện:

docker-compose -f ~/hello_world/docker-compose.test.yml -p ci up -d 

Kiểm tra đầu ra của sut container bằng cách thực hiện:

docker logs -f ci_sut_1 
Output
 % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 42 100 42 0 0 3902 0 --:--:-- --:--:-- --:--:-- 4200
Tests passed!

Và cuối cùng, hãy kiểm tra mã thoát của sut container để xác minh xem thử nghiệm của bạn đã đúng chưa:

docker wait ci_sut_1 
Output
0

Sau khi thực hiện lệnh này, giá trị của $? sẽ là 0 nếu các thử nghiệm được thông qua. Nếu không, các thử nghiệm ứng dụng không thành công.

Lưu ý rằng các công cụ CI khác có thể sao chép kho mã và thực thi các lệnh này để kiểm tra xem các thử nghiệm có thông qua các bit mới nhất của ứng dụng mà không lo lắng về các runtime dependencies hay các cấu hình dịch vụ bên ngoài.

Chính nó! Chúng ta đã chạy thành công thử nghiệm của mình trong một môi trường mới được xây dựng giống hệt với môi trường sản xuất.

 

Kết luận

Nhờ có Docker và Docker Compose, chúng ta có thể tự động hóa cách xây dựng một ứng dụng (Dockerfile),cách triển khai một môi trường cục bộ (docker-compose.yml),cách xây dựng một hình ảnh thử nghiệm (Dockerfile.test) và cách thực thi (tích hợp) thử nghiệm (docker-compose.test.yml) cho bất kỳ ứng dụng nào.

Đặc biệt, các ưu điểm khi sử dụng tệp docker-compose.test.yml để kiểm tra là quá trình thử nghiệm là:

  • Automatable: cách một công cụ thực thi docker-compose.test.yml độc lập với ứng dụng đang được thử nghiệm
  • Light-weight: hàng trăm dịch vụ bên ngoài có thể được triển khai trên một máy chủ duy nhất, mô phỏng các môi trường thử nghiệm phức tạp (tích hợp)
  • Agnostic: tránh việc khóa nhà cung cấp CI, và các thử nghiệm có thể chạy trong bất kỳ cơ sở hạ tầng nào và trên bất kỳ hệ điều hành nào hỗ trợ Docker
  • Immutable: các thử nghiệm truyền trên máy cục bộ sẽ thông qua trong công cụ CI của bạn

Hướng dẫn này cho thấy một ví dụ về cách thử nghiệm ứng dụng "Hello World" đơn giản.

Bây giờ là lúc để sử dụng các tệp ứng dụng của riêng bạn, Dockerize các tập lệnh thử nghiệm ứng dụng của riêng bạn và tạo docker-compose.test.yml của riêng bạn để kiểm tra ứng dụng trong một môi trường mới và không thay đổi.