M l ops Docker

Đóng gói AI model theo kiểu Online Inference sử dụng Docker

Đóng gói AI model theo kiểu Online Inference sử dụng Docker

Đã bao giờ bạn gặp tình huống:

Tại sao code trên máy tính của tôi chạy mà mang sang máy tính của bạn lại không chạy?

99% câu trả lời cho câu hỏi này là do sự khác biệt về môi trường giữa 2 máy tính, 1% còn lại là do các nguyên nhân khác như copy thiếu file, sai đường dẫn, sử dụng câu lệnh không đúng, …

Trong bài toán AI, tình trạng này lại càng phổ biến hơn, bởi vì một model AI yêu cầu cơ man nào là thư viện đi kèm, thư viện này liên kết, ràng buộc với thư viện kia. Không những thế, với tốc độ phát triển như vũ bão hiện nay của AI, các thư viện cũng liên tục cập nhật phiên bản mới, và có khi code sử dụng phiên bản cũ lại không chạy được trên phiên bản mới. Rồi thì thư viện A phiên bản 1.x lại chỉ tương thích với thư viện B phiên bản 1.x.x, nếu ta cứ nhắm mắt gõ pip install abc thì mặc định sẽ là phiên bản mới nhất. Rất rất nhiều vấn đề xung đột thư viện xảy ra trong phát triển một bài toán AI trên nhiều máy tính khác nhau hoặc nhiều người cùng làm việc.

Vấn đề đặt ra lúc này là phải làm sao cô lập được môi trường phát triển dành riêng cho 1 bài toán AI cụ thể. Môi trường đó phải tách biệt hoàn toàn với môi trường trên máy tính, và phải dễ dàng di chuyển giữa nhiều máy tính với nhau.

Một số công cụ đã ra đời để hỗ trợ giải quyết vấn đề này bằng cách tạo ra các môi trường ảo. Có thể kể đến như anaconda, venv, … Mỗi loại đều có những ưu nhược điểm riêng, và phụ thuộc vào thói quen sử dụng của mỗi người. Cá nhân mình cũng đã từng sử dụng qua các loại kể trên nhưng thấy chúng vẫn chưa thể giải quyết được triệt để vấn đề về xung đột môi trường …

Cho đến khi mình biết đến Docker, một công cụ rất powerfull, rất tuyệt vời. Có thể nói docker đã giải quyết được tận gốc vấn đề làm đau đầu những nhà phát triể n AI bấy lâu nay.

Trong bài này, chúng ta sẽ cùng nhau tìm hiểu về docker và cách sử dụng nó trong viêc đóng gói một AI model để thực hiện Inference theo kiểu Online Inference.

1. Docker là gì?

Theo định nghĩa chính thức tại trang chủ của docker thì:

Docker is an open platform for developing, shipping, and running applications.

Hiểu một cách đơn giản thì docker là một nền tảng mã nguồn mở cho việc phát triển, chạy và phân phối các ứng dụng. Nó cho phép chúng ta tách biệt ứng dụng ra khỏi kiến trúc hạ tầng chung của toàn hệ thống và dễ dang mang toàn bộ ứng dụng đó (bao gồm cả môi trường thực thi) sang một máy tính hoàn toàn mới. Điều này giúp các nhà phát triển ứng dụng giảm được thời gian đáng kể ở công đoạn đưa sản phẩm vào sử dụng trong thực tế.

Một số khái niệm cần biết khi làm việc với docker:

  • Docker image: Là một file không thể thay đổi (read-only), chứa toàn bộ source code, thư viện, công cụ, … cần thiết để một ứng dụng có thể chạy được.
  • Docker container: Là một “bản sao”, hay một “instance” của docker image tại thời điểm khởi chạy docker image. Và thực tế là chúng ta chỉ làm việc trên các containers chứ không làm việc với các images. Sau khi kết thúc phiên làm việc thì container sẽ biến mất, và các thay đổi của container đó sẽ không được lưu lại vào docker image sinh ra container đó. Nếu bạn muốn lưu lại các thay đổi bạn đã thực hiện thì có thể sử dụng lệnh “docker commit”, nhưng nó sẽ tạo ra một docker image mới bao gồm docker image cũ và phần thay đổi. Đối với sự thay đổi trên các file, thư mục, ta có thể lưu lại sự thay đổi để sử dụng ở nơi khác mà không cần tạo docker image mới bằng cách đặt các file cần thay đổi ở thư mục chung, chia sẻ với máy tính bên ngoài (host).
  • Docker hub: Là một kho (repository) chứa các docker images, cho phép bạn chia sẻ các docker images của bạn cho người khác bằng cách upload nó lên docker hub. Khi người nào muốn sử dụng docker image của bạn, họ chỉ cần tải về để sử dụng.
  • Host: Là máy tính cài đặt docker và chạy các docker containers.

2. Cài đặt Docker

Để sử dụng docker thì trước tiên cần phải cài đặt docker engine. Các cài đặt khá đơn giản, hãy làm theo hướng dẫn trên trang chủ của docker.

Sau khi cài xong docker, hãy thử chạy lệnh sau:

$ docker run tensorflow/tensorflow:2.3.0-gpu

Nếu thấy output như sau tức là ta đã cài đặt thành công:

Ở đây, tensorflow/tensorflow:2.3.0-gpu là docker image trên docker hub, được cài đặt sẵn tensorflow 2.3.0 và cuda.

Kiểm tra image vừa tải về trong danh sách:

$ docker images

Kết quả:
```python
REPOSITORY              TAG         IMAGE ID       CREATED       SIZE
tensorflow/tensorflow   2.3.0-gpu   3b8d4cbd6723   3 weeks ago   3.18GB

Nếu bạn muốn sử dụng GPU (giả sử là NVIDIA) trong docker thì bạn cần thêm 2 điều kiện:

  • Máy tính của bạn phải có GPU và đã cài đặt đầy đủ driver, cuda, cudnn (có thể sử dụng GPU bình thường trong các task DL mà không sử dụng docker).
  • Cài thêm NVIDIA Container Tookit theo hướng dẫn ở đây

Như trên máy tính của mình đã có đủ 2 điều kiện trên, mình kiểm tra GPU bên trong docker như sau:

$ docker run --gpus all --rm tensorflow/tensorflow:2.3.0-gpu nvidia-smi

Kết quả:

Hoặc chi tiết hơn:

$ docker run --gpus all --rm tensorflow/tensorflow:2.3.0-gpu python -c "import tensorflow as tf; print(tf.reduce_sum(tf.random.normal([1000, 1000])))"

Kết quả:

Trong đó:

  • –gpus all: Cho phép sử dụng GPU trong docker.
  • –rm: Xóa docker container sau khi chạy lệnh xong.

Để cho phép mặc định sử dụng GPU trong docker (không cần sử dụng –gpus all), bạn có thể làm như sau:

  • Thêm default-runtime": "nvidia" vào trong file /etc/docker/daemon.json
# filename: /etc/docker/daemon.json
{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}
  • Khởi động lại docker:
$ sudo pkill -SIGHUP dockerd

Mình đã tổng hợp lại các lệnh hay sử dụng của docker ở phần phụ lục. Các bạn có thể tham khảo thêm.

3. Xây dựng uWSGI docker image

Bên cạnh những images được xây dựng sẵn và chia sẻ trên docker hub, docker cũng hỗ trợ bạn tự build các images cho riêng bạn, phù hợp với từng nhu cầu của bạn. Tất cả được thực hiện thông qua 1 file cấu hình, gọi là Dockerfile.

Trong phần này, ta sẽ cùng nhau xây dựng một DL docker image, bao gồm toàn bộ source code ở bài trước. Ta cũng cấu hình Flask, uWSGI trong docker image để chạy được source code đó.

3.1 Bước 1

Tạo một thư mục tên là uwsgi, và copy toàn bộ source code của bài trước (bao gồm cả model, bỏ đi file client.py vì ta sẽ chạy client ở bên ngoài docker) vào thư mục vừa tạo.

3.2 Bước 2

Tạo file requirements.txt chứa toàn bộ thư viện cần dùng để chạy code (cũng đặt trong thư mục uWSGI). Bạn có thể sinh ra file này tự động bằng lệnh pip freeze > requirements.txt. Tuy nhiên, nếu làm theo cách này thì file requirements.txt sẽ chứa rất nhiều thư viện không cần thiết, bởi vì hầu hết chúng phụ thuộc vào các thư viện khác. Nếu bạn theo dõi từ đầu, bạn chắc chắc biết rằng, ta sẽ chỉ cần những những thư viện sau là đủ: tensorflow, uwsgi, flask, opencv. Trong đó, vì mình dự định không build docker image từ đầu mà kế thừa từ 1 image đã build sẵn (cụ thể là tensorflow/tensorflow:2.3.0-gpu đã tải về ở phần trước) nên tensorflow đã được tích hợp sẵn, không cần cài lại nữa. Cuối cùng, file requirements.txt của chúng ta chỉ như sau:

Flask==1.1.2
uWSGI==2.0.18
opencv-python==4.4.0.46

3.3 Bước 3

Tạo file cấu hình cho uWSGI. Vì mình muốn kiểm tra riêng sự hoạt động của uWSGI nên file cấu hình sẽ như sau:

[uwsgi] 
http = 0.0.0.0:8080
wsgi-file = server.py
callable = app
die-on-term = true
processes = 4
threads = 2
chdir = /uwsgi
master = false 
vacuum = truemodule

Trong phần sau, chúng ta sẽ kết hợp thêm Nginx. Khi đó sẽ cần thay đổi lại cấu hình của uWSGI lại một chút.

3.3 Bước 4

Tạo Dockerfile (trong thư mục uwsgi) chứa các thông tin cấu hình cần thiết để tạo docker image. Nội dung của file này như sau:

FROM tensorflow/tensorflow:2.3.0-gpu # kế thừa từ image tensorflow/tensorflow:2.3.0-gpu
WORKDIR /uwsgi # thư mục làm viêc mặc định bên trong docker
ADD . /uwsgi # local folder để copy vào thư mục làm việc của docker, chính là thư mục chúng ta tạo ở bước 1
RUN pip install -r requirements.txt # cài đặt các thư viện cần thiết trong file requirements.txt
RUN apt-get update 
RUN apt-get install ffmpeg libsm6 libxext6  -y # sửa lỗi opencv, thử bỏ đi để xem điều gì xảy ra?
CMD ["uwsgi", "app.ini"] # chạy lệnh "uwsgi app.ini" khi khởi chạy docker image

Có rất rất nhiều tùy chọn khi viết Dockerfile, tham khảo ở đây nếu bạn cần thêm thông tin.

Thự mục uwsgi lúc này sẽ như sau:

├── animal_model_classification.h5
├── app.ini
├── cat.1.jpg
├── Dockerfile
├── dog.1.jpg
├── requirements.txt
└── server.py

Trong đó, 2 files ảnh là để chúng ta thực hiện việc test về sau.

4 Build docker image

OK, mọi thứ cần thiết đã chuẩn bị xong, ta sẽ chạy lệnh sau để buidl docker image:

$ docker build -t image-classification-production:1.0 .

Docker image được sinh ra sẽ có tên là image-classification-production, kèm theo tag 1.0 để phân biệt nó với các phiên bản khác trong tương lai.

Nếu build, thành công, output sẽ như sau:

 ---> a2a60f32471b
Step 7/7 : CMD ["uwsgi", "app.ini"]
 ---> Running in 3776d496ca68
Removing intermediate container 3776d496ca68
 ---> 53150d1373a3
Successfully built 53150d1373a3
Successfully tagged image-classification-production:1.0

Kiểm tra docker image trong danh sách:

docker images

Kết quả:

REPOSITORY                        TAG         IMAGE ID       CREATED              SIZE
image-classification-production   1.0         53150d1373a3   About a minute ago   5.37GB
tensorflow/tensorflow             2.3.0-gpu   3b8d4cbd6723   3 weeks ago          3.18GB

5 Chạy docker image

Để chạy docker image vừa tạo, ta sử dụng lệnh sau:

$ docker run --rm --publish 80:8080  --name dlp  image-classification-production:1.0

Có 2 cái mà ta phải chú ý ở đây:

  • Tham số --public 80:8080 sẽ “expose” port 8080 của container tới port 80 của host. Nói cách khác, tất cả các requests đến địa chỉ localhost:80 sẽ được chuyển tiếp đến địa chỉ 0.0.0.0:8080 bên trong container. 8080 được gọi là listening port của uWSGI.
  • Tham số --name dlp sẽ đặt tên cho container là dlp. Ta nên đặt tên cho container để dễ làm việc với nó hơn. Ngược lại, docker sẽ tạo cho nó một ID ngẫu nhiên.

Kết quả:

2021-01-06 02:52:45.347188: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-01-06 02:52:45.347580: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:982] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-01-06 02:52:45.347925: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1402] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 4676 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1660 Ti with Max-Q Design, pci bus id: 0000:01:00.0, compute capability: 7.5)
2021-01-06 02:52:47.271932: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 536870912 exceeds 10% of free system memory.
2021-01-06 02:52:47.621364: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 536870912 exceeds 10% of free system memory.
2021-01-06 02:52:47.918398: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 536870912 exceeds 10% of free system memory.
2021-01-06 02:52:48.759371: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 536870912 exceeds 10% of free system memory.
2021-01-06 02:52:49.637126: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 536870912 exceeds 10% of free system memory.
WSGI app 0 (mountpoint='') ready in 8 seconds on interpreter 0x55cf948bc720 pid: 1 (default app)
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 1, cores: 1)

Ta quan sá thấy container đã chạy thành công và uWSGI cũng đã được khởi động.

Lưu ý: Trong trường hợp port 80 đã được sử dụng bới ứng dụng khác (nginx trong bài trước chẳng hạn), bạn phải close ứng dụng đó hoặc sử dụng một port khác.

Để kiểm tra xem uWSGI có làm viêc đúng hay không, ta có thể sử dụng lại client đã chuẩn bị từ bài trước (nhớ đổi port của ENDPOINT_URL từ 8080 thành 80).

$ python client.py

Kết quả:

b'cat'

Như vậy là uWSGI đã được cài đặt thành công vào docker.

Lưu ý: Trong quá trình viết bài này, mình gặp lỗi liên quan đến cuda khi chạy test uWSGI. Mình xóa hết các docker images đi và chạy lại từ đầu thì không bị lỗi nữa.

6. Xây dựng Nginx docker image

Tương tự như việc xây dựng uWSGI docker image, chúng ta sẽ đi build một Nginx docker image, đặt trước uWSGI server thực hiện vai trò như một reverse proxy.

6.1 Bước 1

Tạo thư mục nginx, cùng cấp với thư mục uwsgi.

6.2 Bước 2

Tạo file cấu hình Nginx, tên là nginx.conf, đặt trong thư mục nginx, với nội dung như sau:

server {
  listen 80;

  location / {
    include uwsgi_params;
    uwsgi_pass  uwsgi:660 ;
  }

Với cấu hình này thì Nginx sẽ lắng nghe trên port 80, chuyển tiếp các requests đến port 660 của uWSGI server thông qua socket (sử dụng giao thức uwsgi).

6.3 Bước 3

Cập nhật lại cấu hình của uWSGI (file app.ini) để làm việc được với Nginx, như sau:

module = server
socket= :660
callable = app
die-on-term = true
processes = 1
master = false
vacuum = true

6.4 Bước 4

Tạo file Dockerfile cho Nginix docker trong thư mục nginx. Nginix docker image được kế thừa từ nginx image trên docker hub, ta chỉ việc thay thế cấu hình mặc định của nó bằng cấu hình mà ta vừa tạo ở bước 3.

FROM nginx

RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/

Đến đây, nếu chạy lệnh docker build ... thì ta sẽ có được nginx docker image. Nhưng nếu chỉ chạy một mình image này thì không có tác dụng gì cả. Ta cần phải kết hợp cả 2 docker images uwsgi và nginx. Đó chính là công viêc của docker-compose.

7. Chạy đồng thời nhiều docker containers với Docker Compose

Liệu bạn có thắc mắc rằng tại sao ta không build cả Nginx và uWSGI vào chung 1 docker image? Chẳng phải như thế sẽ tiện hơn hay sao?

Câu trả lời là không nên làm vậy. Theo kiến trúc làm việc kết hợp giữa Nginx và uWSGI thì một Nginx instance có thể kết hợp với nhiề u uWSGI instances. Nếu ta kết hợp chung lại, sẽ không tận dụng được khả năng này. Thêm nữa, dung lượng của docker image sẽ rất lớn nếu ta kết hợp lại.

Mở rộng ra, nếu một hệ thống của chúng ta bao gồm cả database, backend, front-end, messaging systems, task queue, … ta không thể chạy tất tần tật mọi thứ trong một docker container được.

Từ góc độ của nhà phát triển phần mềm, docker-compose chỉ là một file cấu hình, định nghĩa tất cả containers và cách thức mà các containers đó tương tác với nhau.

7.1 Cài đặt docker-compose

Để cài đặt docker-compose. Bạn hãy làm theo hướng dẫn sau trên trang chủ của docker.

7.2 Định nghĩa cấu hình của docker-compose

Tạo file docker-compose.yml (bên ngoài 2 thư mục uwsgi và nginx), với nội dung như sau:

version : "3.7"

services:
  uwsgi:
    build: ./uwsgi
    container_name: uwsgi_img_classification
    restart: always
    expose:
      - 660

  nginx:
    build: ./nginx
    container_name: nginx
    restart: always
    ports:
      - "80:80"

Phần chính của cấu hình này là khai báo 2 containers, gọi là 2 services. Hai tham số quan trọng của mỗi services là:

  • build: thư mục chứa Dockerfile và các files cần thiết của mỗi container.
  • restart: tự động khởi động lại service nếu xay ra lỗi.
  • expose: uwsgi lắng nghe request đến trên port 660 (chỉ trong phạm vi docker).
  • port: nginx mở port 80 ra bên ngoài (có thể chọn tùy ý) để lắng nghe requests đến, ánh xạ đến port 80 (theo như cấu hình trong file nginx.conf) của container.

Như vậy, có thể tóm tắt lại flow như sau:

  • Các requests từ clients đến port 80 của host.
  • Các requests được ánh xạ sang port 80 của nginx container.
  • Các requests tiếp tục được chuyển tiếp đến port 660 của uwsgi container.
  • uwsgi gọi Flask endpoint và thực hiện quá trình nhận diện.
  • uwsgi gửi lại kết quả nhận diện theo hướng ngược lại.

7.3 Build docker-compose

Chạy lệnh sau để build docker-compose với cả 2 containers.

$ docker-compose build

Nếu build thành công, output sẽ như sau:

Step 7/7 : CMD ["uwsgi", "app.ini"]
 ---> Running in 9608e1187e82
Removing intermediate container 9608e1187e82
 ---> 357fe8e41768

Successfully built 357fe8e41768
Successfully tagged docker_uwsgi:latest
Building nginx
Step 1/3 : FROM nginx
latest: Pulling from library/nginx
6ec7b7d162b2: Pull complete
cb420a90068e: Pull complete
2766c0bf2b07: Pull complete
e05167b6a99d: Pull complete
70ac9d795e79: Pull complete
Digest: sha256:4cf620a5c81390ee209398ecc18e5fb9dd0f5155cd82adcbae532fec94006fb9
Status: Downloaded newer image for nginx:latest
 ---> ae2feff98a0c
Step 2/3 : RUN rm /etc/nginx/conf.d/default.conf
 ---> Running in 11140e051282
Removing intermediate container 11140e051282
 ---> 1fcc92cfdfc4
Step 3/3 : COPY nginx.conf /etc/nginx/conf.d/
 ---> 21bda0089cca

Successfully built 21bda0089cca
Successfully tagged docker_nginx:latest

Kiểm tra thử danh sách images bằng lệnh docker images:

REPOSITORY                        TAG         IMAGE ID       CREATED         SIZE
docker_nginx                      latest      21bda0089cca   4 minutes ago   133MB
docker_uwsgi                      latest      357fe8e41768   5 minutes ago   5.37GB
image-classification-production   1.0         bd9928abee21   2 hours ago     5.37GB
nginx                             latest      ae2feff98a0c   3 weeks ago     133MB
tensorflow/tensorflow             2.3.0-gpu   3b8d4cbd6723   3 weeks ago     3.18GB

Ta thấy hai containers docker_nginxdocker_uwsgi đã xuất hiện.

7.4 Kiểm tra hoạt động của hệ thống

Ta sẽ khởi động các containers lên để kiểm tra thử xem hê thống có làm việc chính xác không.

$ docker-compose up

Khởi động thành công:

Starting nginx                    ... done
Starting uwsgi_img_classification ... done
Attaching to nginx, uwsgi_img_classification
nginx    | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx    | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
uwsgi_img_classification | [uWSGI] getting INI configuration from app.ini
.....
uwsgi_img_classification | 2021-01-06 09:18:12.292414: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1402] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 4662 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1660 Ti with Max-Q Design, pci bus id: 0000:01:00.0, compute capability: 7.5)
uwsgi_img_classification | 2021-01-06 09:18:14.386546: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 536870912 exceeds 10% of free system memory.
uwsgi_img_classification | 2021-01-06 09:18:14.737805: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 536870912 exceeds 10% of free system memory.
uwsgi_img_classification | 2021-01-06 09:18:15.045424: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 536870912 exceeds 10% of free system memory.
uwsgi_img_classification | 2021-01-06 09:18:16.238951: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 536870912 exceeds 10% of free system memory.
uwsgi_img_classification | 2021-01-06 09:18:17.246651: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 536870912 exceeds 10% of free system memory.
uwsgi_img_classification | WSGI app 0 (mountpoint='') ready in 7 seconds on interpreter 0x56494b98c680 pid: 1 (default app)
uwsgi_img_classification | uWSGI running as root, you can use --uid/--gid/--chroot options
uwsgi_img_classification | *** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
uwsgi_img_classification | *** uWSGI is running in multiple interpreter mode ***
uwsgi_img_classification | spawned uWSGI worker 1 (and the only) (pid: 1, cores: 1)

Chạy client để nhận diện: python client.py.

Kết quả:

b'cat'

8. Kết luận

Phù, thật tuyệt vời, mọi thứ đã chạy đúng như mong muốn.

Bài hôm nay khá là dài và khó. Mình đã phải thực hiện cài cắm rất nhiều lần để có thể hoàn thành bài viết này. Hi vọng sẽ có ích cho các bạn trong việc tìm kiếm giải pháp triể n khải AI model vào trong các sản phẩm để đưa đến tay người dùng!

Toàn bộ source code sử dụng trong bài này, các bạn có thể tham khảo trên github cá nhân của mình tại đây. Giống như bài trước, vì model animal_model_classification.h5 có dung lượng khá lớn (> 1.5GB) nên mình không upload lên github được. Các bạn hãy sử dụng model của chính mình để thực hành nhé!

Trong các bài viết tiếp theo, mình sẽ sử dụng docker để train một model khác và thực hiện batch inference bằng model đó. Mời các bạn đón đọc!

9. Phụ lục một số lệnh cơ bản của Docker

1. List docker image
$ docker images

2. List container
$ docker ps <-a>

3. Run a docker
$ docker run -it [image_name] bash

4. Access to running container
$ docker exec -it [container_id or container_name] bash

5. Commit change of container to docker image
$ docker commit [container_name or container_id] [new_image_name]

6. Stop running container
$ docker stop [container_id or container_name]
$ docker stop $(docker ps -aq) # Stop all container

7. Start stoped container
$ docker start [container_id or container_name]

8. Remove container
$ docker rm [container_id or container_name]
$ docker rm $(docker ps -aq) # Remove all

9. Export container
$ docker export [container_id or container_name] | gzip > file_export.tar.gz

10. Import docker => images
$ zcat  file_export.tar.gz | docker [new_name_image]
$ docker images # check

11. Remove docker image
$ docker rmi [image_name]


Loi: docker: Error response from daemon: Unknown runtime specified nvidia.
Solution:
1. 
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

2.
$ sudo mkdir -p /etc/systemd/system/docker.service.d
$ sudo tee /etc/systemd/system/docker.service.d/override.conf <<EOF
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd --host=fd:// --add-runtime=nvidia=/usr/bin/nvidia-container-runtime
EOF
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker


** Move docker image to other computer
1. Save images
$ docker save <REPOSITORY> > <images_name>.tar
2. Load images
$ docker load < <images_name>.tar 
3. Run images
$ docker run -it  --runtime=nvidia --rm  --net=host --privileged <Image ID>

10. Tham khảo