อยากลองใช้ docker แต่ยังไม่ต้องการนำ image อัปโหลดไปไว้บน docker hub จะทำอย่างไรได้มั้ย ที่นี่มีคำตอบครับ
เราสามารถนำ docker image ที่ได้สร้างขึ้นนั้นไปเก็บไว้ในสิ่งที่เรียกว่า Docker registry ซึ่งแบ่งได้เป็น 2 อย่างคือ Public registry อยู่ที่ hub.docker.com เราจะต้องลงทะเบียนเพื่อขอมีบัญชีผู้ใช้จึงจะสามารถอัปโหลด image ไปเก็บไว้ได้ ส่วนอีกอย่างก็คือ Private (Local) registry จะเป็นการสร้างที่เก็บส่วนตัว ที่เก็บของหน่วยงาน ในบทความนี้จะสาธิตทำที่เก็บ image สำหรับทดสอบงาน
การใช้งาน Docker public registry ต้องมี user account ที่ cloud.docker.com
จะต้อง login ก่อนจึงจะ push image ขึ้นไปได้ เหมือนที่แสดงตัวอย่างไว้ในบล็อก “เตาะแตะไปกับ Docker ตอนที่ 1”
$ docker login
ตัวอย่างคำสั่ง push ที่ผมนำ image ไปเก็บไว้
$ docker push woonpsu/docsdocker:part1
ซึ่งเรียกใช้จากที่เครื่องใดก็ได้ ด้วยคำสั่ง pull
$ docker pull woonpsu/docsdocker:part1
แต่หากเรายังไม่พร้อมที่จะนำ image ไปไว้บนนั้น เราก็ทำ Local registry ไว้ใช้เองไปพราง ๆ ก่อน ทำได้ 2 แบบ คือ
1. Local registry ที่ใช้งานภายในเครื่องของเราเครื่องเดียว
2. Local registry ที่เราเปิดให้เครื่อง client อื่น ๆ เข้ามาใช้ร่วมได้
Local registry แบบที่ใช้งานภายในเครื่องของเราเครื่องเดียว (localhost:5000)
ใช้คำสั่งนี้เพื่อเริ่มต้นสร้าง registry container
$ docker run -d -p 5000:5000 --restart=always --name myregistry registry:2
จากนั้นเรา pull image สักอัน จาก hub.docker.com เช่น
$ docker pull ubuntu:16.04
หลังจากดัดแปลง(ไม่ทำก็ได้)ตามต้องการแล้วก็ใส่ tag localhost:5000/my-ubuntu ดังนี้
$ docker tag ubuntu:16.04 localhost:5000/my-ubuntu $ docker images
แล้วก็ push image ไปยัง local registry ซึ่งก็คือ เครื่องที่เรากำลังใช้งาน (localhost) ใช้ port หมายเลข 5000 ดังนี้
$ docker push localhost:5000/my-ubuntu
ซึ่งวิธีการเรียกใช้งาน image ที่เก็บไว้นั้น เป็นดังนี้
$ docker pull localhost:5000/my-ubuntu
ก่อนไปทำตัวอย่างถัดไปซึ่งเป็นแบบที่ 2 ให้ลบ container ชื่อ myregistry ที่ทดสอบเสร็จแล้ว ที่ต้องลบเพราะว่าใช้ port หมายเลขเดียวกัน หากใช้หมายเลข port ต่างกัน ก็ไม่ต้องลบ
$ docker stop myregistry $ docker rm myregistry
Local registry แบบที่เราเปิดให้เครื่อง client อื่น ๆ เข้ามาใช้ร่วมได้ (docker-registry.localdomain:5000)
เราจะต้องเริ่มต้นที่การกำหนดชื่อเครื่อง ผมสมมติตั้งชื่อว่า docker-registry.localdomain ให้กับ host ที่ติดตั้ง docker registry ใครจะตั้งอย่างไรก็ได้ครับ
ในบทความนี้ เนื่องจากว่า ผมจะทดสอบแบบไม่ได้ไปจด Domain Name จริงให้กับเครื่อง ผมจะต้องแก้ไขไฟล์ /etc/hosts และ /etc/hostname ดังนี้
ที่ไฟล์ /etc/hosts ให้เพิ่มบรรทัด
10.168.16.19 docker-registry.localdomain
ที่ไฟล์ /etc/hostname ให้เปลี่ยนชื่อเครื่องจากเดิม มาเป็นดังนี้
docker-registry.localdomain
เสร็จแล้ว reboot เครื่อง
ขั้นตอนการตั้งค่า มาดูกันครับ
เริ่มต้นที่เครื่อง docker-registry.localdomain
ให้ทำคำสั่งตั้งค่า TLS certificate เพราะว่าจำเป็นต้องใช้ด้วย (หากมี certificate ของจริงก็นำมาใช้แทน domain.crt และ domain.key ได้เลย)
$ cd $ mkdir certs $ openssl req \ -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \ -x509 -days 365 -out certs/domain.crt
จะมีการถามให้เติมข้อมูล เอาคล้าย ๆ ตัวอย่างก็ได้
Generating a 4096 bit RSA private key writing new private key to 'certs/domain.key' Country Name (2 letter code) [AU]:TH State or Province Name (full name) [Some-State]:SK Locality Name (eg, city) [ ]:HDY Organization Name (eg, company) [Internet Widgits Pty Ltd]:PSU Organizational Unit Name (eg, section) [ ]:CC Common Name (e.g. server FQDN or YOUR name) [ ]:docker-registry.localdomain Email Address [ ]:
จะพบว่าในไดเรกทอรี certs จะเกิดไฟล์ 2 ไฟล์
$ ls certs/ domain.crt domain.key
ใช้คำสั่ง docker run สร้าง container และสมมติตั้งชื่อว่า netregistry
$ docker run -d --restart=always --name netregistry \ -v `pwd`/certs:/certs \ -e REGISTRY_HTTP_ADDR=0.0.0.0:5000 \ -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \ -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \ -p 5000:5000 \ registry:2
ต่อไปจะเป็นการทดสอบการใช้งาน local registry
ใส่ tag ก่อนที่จะ push ดังนี้
$ docker tag ubuntu:16.04 docker-registry.localdomain:5000/my-ubuntu $ docker images
แล้ว push image เก็บไว้ใน local registry
$ docker push docker-registry.localdomain:5000/my-ubuntu
ไปที่เครื่อง client สมมติตั้งชื่อ hostname ว่า docker-vm3
ที่ไฟล์ /etc/hosts ให้เพิ่มบรรทัด
127.0.1.1 docker-vm3 10.168.16.19 docker-registry.localdomain
ที่ไฟล์ /etc/hostname เป็นดังนี้
docker-vm3
เสร็จแล้ว reboot เครื่อง
ต่อไปก็ทดสอบ pull image จาก local registry ที่ทำขึ้นนั้น
$ docker pull docker-registry.localdomain:5000/my-ubuntu $ docker images
ต่อไปก็ทดสอบ push image โดยเราก็ไปเอา image จาก hub.docker.com มาสัก 1 อัน ใส่ tag แล้ว push ดังนี้
$ docker pull woonpsu/docsdocker:part1 $ docker tag woonpsu/docsdocker:part1 docker-registry.localdomain:5000/helloworld $ docker push docker-registry.localdomain:5000/helloworld
จะพบว่าเราสามารถ push image ไปยังเครื่อง local registry ได้ด้วย
วิธีที่แนะนำไปแล้วข้างต้น เป็นการสร้าง Local registry ที่ไม่ได้มีความปลอดภัย เพราะว่าแค่รู้ชื่อเครื่อง รู้หมายเลข port (เลือกทดสอบกับ port 5000) ก็สามารถ push image ได้แล้ว
ดังนั้นหากจะสร้าง Local registry ให้บริการ (production) เราก็ต้องทำขั้นตอนเพิ่มอีกคือต้องใช้ TLS certificate ร่วมกับ Access control
ดังนี้
ที่เครื่อง docker-registry.localdomain
สร้าง username ที่มีสิทธิจะเข้ามา (access) ใช้ local registry สมมติชื่อ testuser และรหัสผ่านคือ testpassword ดังนี้
$ mkdir auth $ docker run \ --entrypoint htpasswd \ registry:2 -Bbn testuser testpassword > auth/htpasswd $ cat auth/htpasswd testuser:$2y$05$UMOEA8bdBqSbHp/2LfiQ/uxLkf5IkXNqNE8V3Mp2IR/fRCsLXE5Q2
รัน container ตั้งชื่อว่า privateregistry และเราจะเปลี่ยนมาใช้ port 443 ดังนี้
$ docker run -d \ --restart=always \ --name privateregistry \ -v `pwd`/auth:/auth \ -e "REGISTRY_AUTH=htpasswd" \ -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \ -v `pwd`/certs:/certs \ -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \ -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \ -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \ -p 443:443 \ registry:2
ไปที่เครื่อง client ชื่อ docker-vm3
$ docker login docker-registry.localdomain Username: testuser Password:
ทดสอบ push image
$ docker tag woonpsu/docsdocker:part1 docker-registry.localdomain/sawadee $ docker push docker-registry.localdomain/sawadee
ลองทดสอบดูว่าหากไม่ได้ login ก็จะ push ไม่ได้
$ docker logout docker-registry.localdomain $ docker push docker-registry.localdomain/sawadee The push refers to a repository [docker-registry.localdomain/sawadee] 0d960f1d4fba: Preparing no basic auth credentials
ข้อควรระวังในการทำ local registry คือ image ที่เรานำไปเก็บไว้ จะอยู่ใน container ซึ่งหากเราลบ container ด้วยคำสั่ง
$ docker stop privateregistry $ docker rm privateregistry
ก็จะเป็นการลบ image ทั้งหมด
ดังนั้น เราจะต้องศึกษาวิธี mount volume เข้าไปใน container เพื่อให้ image ที่ push ไว้นั้น ถูกเก็บใน file system ของเครื่อง host แทน โดยเพิ่มบรรทัด -v นี้เข้าไปด้วยวางไว้ก่อนบรรทัดสุดท้าย (registry:2)
-v /mnt/registry:/var/lib/registry \
โดยที่ /mnt/registry คือ file system บน host และ /var/lib/registry คือไดเรกทอรีใน container
ขอให้สนุกกับการทดลองเล่น docker กันนะครับ
Reference:
https://docs.docker.com/registry/deploying/
https://docs.docker.com/registry/deploying/#restricting-access