<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Bizfly Cloud Engineering]]></title><description><![CDATA[Blog of our latest news, updates, and stories for developers]]></description><link>http://engineering.bizflycloud.vn/</link><image><url>http://engineering.bizflycloud.vn/favicon.png</url><title>Bizfly Cloud Engineering</title><link>http://engineering.bizflycloud.vn/</link></image><generator>Ghost 3.12</generator><lastBuildDate>Sat, 18 Apr 2026 12:25:02 GMT</lastBuildDate><atom:link href="http://engineering.bizflycloud.vn/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Cài đặt Pritunl VPN và sử dụng]]></title><description><![CDATA[<figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-0.png" class="kg-image"></figure><p><strong>Mục tiêu</strong>: Từ client có thể conenct tới mạng VPC network thông qua VPN-server-Pritunl.</p><p><strong>Phân hoạch địa chỉ IP</strong></p><ul><li>VPN server:</li><li>IP public: 103.56.156.114</li><li>IP VPC: 10.20.1.47</li><li>VM local</li><li>IP VPC: 10.20.1.91</li></ul><p><strong>Yêu cầu</strong>: Client có thể connect tới VM local</p>]]></description><link>http://engineering.bizflycloud.vn/cai-dat-pritunl-vpn-va-su-dung/</link><guid isPermaLink="false">6142ff34bd998300805d6c4f</guid><dc:creator><![CDATA[ThaoBTP]]></dc:creator><pubDate>Thu, 16 Sep 2021 08:24:42 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-0.png" class="kg-image"></figure><p><strong>Mục tiêu</strong>: Từ client có thể conenct tới mạng VPC network thông qua VPN-server-Pritunl.</p><p><strong>Phân hoạch địa chỉ IP</strong></p><ul><li>VPN server:</li><li>IP public: 103.56.156.114</li><li>IP VPC: 10.20.1.47</li><li>VM local</li><li>IP VPC: 10.20.1.91</li></ul><p><strong>Yêu cầu</strong>: Client có thể connect tới VM local dải 10.20.1.91.</p><h4 id="c-c-b-c-c-i-t-tr-n-vpn-server">Các bước cài đặt trên VPN-server</h4><blockquote>apt-get update</blockquote><blockquote>apt-get -y upgrade</blockquote><blockquote>echo "deb http://repo.pritunl.com/stable/apt focal main" | sudo tee /etc/apt/sources.list.d/pritunl.list</blockquote><blockquote>echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list</blockquote><blockquote>curl -fsSL https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -</blockquote><blockquote>apt-key adv --keyserver hkp://keyserver.ubuntu.com --recv E162F504A20CDF15827F718D4B7C549A058F8B6B</blockquote><blockquote>apt-key adv --keyserver hkp://keyserver.ubuntu.com --recv 7568D9BB55FF9E5287D586017AE645C0CF8E292A</blockquote><blockquote>apt-get --assume-yes install pritunl mongodb-server</blockquote><blockquote>systemctl start pritunl mongodb</blockquote><blockquote>systemctl enable pritunl mongodb</blockquote><p>Khi truy cập vào IP public thế này nghĩa là truy cập thành công</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-1.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-2.png" class="kg-image"></figure><p>Sau đó dùng lệnh pritunl setup-key để lấy password default</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-3.png" class="kg-image"></figure><p>Thực hiện thay đổi password trong giao diện</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-4.png" class="kg-image"></figure><ul><li>Sau đó add organization và add user</li></ul><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-5.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-6.png" class="kg-image"></figure><p>Sau đó add server: Virtual network là dải IP tunnel</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-7.png" class="kg-image"></figure><p>Sau đó attach Organization vào Server</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-8.png" class="kg-image"></figure><p>Add route đến dải 10.20.1.0/24 (dải mạng VPC)</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-9.png" class="kg-image"></figure><p>Sau đó chọn start server.</p><h5 id="th-c-hi-n-c-p-file-cho-client">Thực hiện cấp file cho client</h5><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-10.png" class="kg-image"></figure><ul><li>Trong phần user chọn Get Two-Step Authentication Key để lấy Google Authentication Key.</li><li>Trong phần user chọn Get Temporary Profile Link để lấy file config ovpn.</li></ul><h3 id="th-c-hi-n-c-i-t-pritunl-client">Thực hiện cài đặt Pritunl client</h3><ul><li>Truy cập <a href="https://client.pritunl.com/#install">https://client.pritunl.com/#install</a> để cài đặt.</li><li>Sau khi cài đặt xong chạy lệnh pritunl-client-electron.</li></ul><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-11.png" class="kg-image"></figure><ul><li>Sau đó Import Profile file ovpn đã được tải về.</li><li>Sau đó chọn connect: Phần enter pin thì nhập pin đã tạo khi tạo user, OTP thì sử dụng Google Authenticator.</li></ul><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-12.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-13.png" class="kg-image"></figure><p>Nhìn ip r đã thấy routing đến dải 10.20.1.0/24 thông qua 192.168.236.1 (chính là dải IP tunnel)</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-14.png" class="kg-image"></figure><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2021/09/pritunl-vpn-15.png" class="kg-image"></figure><p>Docs:</p><ul><li><a href="https://hocchudong.com/pritunl-vpn-phan-1-huong-dan-trien-khai-vpn-bang-pritunl-tren-ubuntu1804/">https://hocchudong.com/pritunl-vpn-phan-1-huong-dan-trien-khai-vpn-bang-pritunl-tren-ubuntu1804/</a></li><li><a href="https://hocchudong.com/pritunl-vpn-phan-2-huong-dan-cai-dat-pritunl-client-tren-linux/">https://hocchudong.com/pritunl-vpn-phan-2-huong-dan-cai-dat-pritunl-client-tren-linux/</a></li><li><a href="https://computingforgeeks.com/install-and-configure-pritunl-vpn-server-on-ubuntu/">https://computingforgeeks.com/install-and-configure-pritunl-vpn-server-on-ubuntu/</a></li></ul>]]></content:encoded></item><item><title><![CDATA[Cài đặt TLS Let's Encrypt tự động trên Kubernetes]]></title><description><![CDATA[<p>Trong bài trước, tôi đã hướng dẫn để cài đặt Nginx Ingress Controller cho cụm Kubernetes. Trong bài này tôi sẽ thiết lập cấu hình TLS Let's Encrypt cho Nginx Ingress. Các TLS Certificate được tự động renew trong cluster.</p><p>Tôi sử dụng cert-manager để thực hiện quản lý các</p>]]></description><link>http://engineering.bizflycloud.vn/cai-dat-ssl-lets-encrypt-tu-dong-tren-kubernetes/</link><guid isPermaLink="false">5f82bca3f35551008215fbd0</guid><category><![CDATA[blog]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Sa Pham]]></dc:creator><pubDate>Mon, 12 Oct 2020 15:34:22 GMT</pubDate><content:encoded><![CDATA[<p>Trong bài trước, tôi đã hướng dẫn để cài đặt Nginx Ingress Controller cho cụm Kubernetes. Trong bài này tôi sẽ thiết lập cấu hình TLS Let's Encrypt cho Nginx Ingress. Các TLS Certificate được tự động renew trong cluster.</p><p>Tôi sử dụng cert-manager để thực hiện quản lý các TLS Certificate. Ngoài việc hỗ trợ Let's Encryption, cert-manager còn hỗ trợ các tính năng như Self-Signed Certificate, CA, Vault. Để tìm hiểu thêm về cert-manager và các tính năng nâng cao bạn có thể truy cập vào document chính thức của cert-manager tại [1].</p><p>Cert-Manager quản lý các resource: Issuer (ClusterIssuer) , Certificates, CertificateRequest.</p><p>Hình sau đây mô tả mối quan hệ giữa Issuer, Certificate, Secret và cert-manager:</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-13.png" class="kg-image"></figure><p><strong>Yêu cầu:</strong></p><p>- helm</p><p>- Nginx Ingress Controller</p><p>Thực hiện add helm repo cho cert-manager</p><!--kg-card-begin: markdown--><pre><code>helm repo add jetstack https://charts.jetstack.io
helm repo update
</code></pre>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-14.png" class="kg-image"></figure><p>Cài đặt cert-manager bằng helm, sử dụng lệnh sau để install cert-manager:</p><!--kg-card-begin: markdown--><pre><code>helm install \
  --name cert-manager \
  --namespace cert-manager \
  --version v1.0.2 \
  jetstack/cert-manager \
  --set installCRDs=true
</code></pre>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-15.png" class="kg-image"></figure><p>Kiểm tra các pod của cert-manager trên namespace cert-manager</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-16.png" class="kg-image"></figure><p>Tạo ClusterIssuer phục vụ cho việc request tới ACME server để generate TLS Certificate</p><p>Bạn có thể sử dụng mẫu ClusterIssuer sau, ngoài ra ta cũng có thể sử dụng Issuer thay cho ClusterIssuer. Điểm khác nhau là với ClusterIssuer thì Issuer Cluster Wide tức là có thể sử dụng ở bất cứ namespace nào. Còn với Issuer chỉ tồn tại trong 1 namespace duy nhất.</p><p>Manifest tạo Cluster Issuer có tên <strong>sapd-issuer </strong>như sau</p><!--kg-card-begin: markdown--><pre><code>apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: sapd-issuer
spec:
  acme:
    # You must replace this email address with your own.
    # Let's Encrypt will use this to contact you about expiring
    # certificates, and issues related to your account.
    email: sapd@vccloud.vn
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      # Secret resource that will be used to store the account's private key.
      name: sapd-ssl
    # Add a single challenge solver, HTTP01 using nginx
    solvers:
    - http01:
        ingress:
          class: nginx

</code></pre>
<!--kg-card-end: markdown--><p>Lưu ý:</p><p>- Điền thông tin email</p><p>- Tên Secret lưu private key với ACME server</p><p> - Server URL. Lưu ý sử dụng acme staging cho test và production khi triển khai thật</p><p>Lưu lại manifest với tên file <strong>cluster-issuer.yml</strong></p><p>Thực hiện tạo cluster-issuer bằng lệnh sau</p><!--kg-card-begin: markdown--><pre><code>kubectl apply -f cluster-issuer.yml
</code></pre>
<!--kg-card-end: markdown--><p>Kiểm tra ClusterIssuer đã được tạo</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-17.png" class="kg-image"></figure><p></p><p>Khởi tạo 1 deployment Nginx để kiểm tra và expose qua service</p><!--kg-card-begin: markdown--><pre><code>kubectl create deploy --image nginx nginx
kubectl expose deploy nginx --port 80
</code></pre>
<!--kg-card-end: markdown--><p>Kiểm tra các resource vừa tạo</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-18.png" class="kg-image"></figure><p>Ta sẽ cần sử dụng 1 domain cho service nginx vừa tạo ra. Tôi sẽ sử dụng domain <strong>ingress-1.k8slab.sapham.net </strong>và trỏ tới IP của Load Balancer là 45.124.94.24</p><p>Tip: Các bạn có thể trỏ wildcard domain vào địa chỉ IP của Load Balancer (Ingress)</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-19.png" class="kg-image"></figure><p>Tạo ingress cho service <strong>nginx </strong>với domain trên. Sử dụng ingress manifest như sau</p><!--kg-card-begin: markdown--><pre><code>apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-2
  annotations:
    kubernetes.io/ingress.class: &quot;nginx&quot;
    cert-manager.io/cluster-issuer: &quot;sapd-issuer&quot;
spec:
  tls:
  - hosts:
    - ingress-1.k8slab.sapham.net
    secretName: ingress-1-ssl
  rules:
  - host: ingress-1.k8slab.sapham.net
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx
          servicePort: 80

</code></pre>
<!--kg-card-end: markdown--><p>Lưu ý: </p><p>- Sử dụng annotation để chỉ định cluster-issuer đã được tạo ở trên</p><p>- Khai báo host cho tls và rule: domain dùng để truy cập vào service</p><p>- Cert-manager sẽ lưu TLS Certificate cấp bởi Let's Encrypt vào Secret</p><p>Sau khi khởi tạo Ingress, ta sẽ thấy cert-manager khởi tạo Certificate, Secret để lưu trữ TLS Cert vừa được Generate.</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-20.png" class="kg-image"></figure><p>Ta có thể kiểm tra thông tin Certificate vừa được khởi tạo bằng lệnh </p><!--kg-card-begin: markdown--><pre><code>kubectl describe cert ingress-1-ssl
</code></pre>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-21.png" class="kg-image"></figure><p></p><p>Truy cập thử vào domain thông qua trình duyệt web</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-22.png" class="kg-image"></figure><p></p><p><strong>References:</strong></p><p>[1] -  <a href="https://cert-manager.io/docs/">https://cert-manager.io/docs/</a></p>]]></content:encoded></item><item><title><![CDATA[Cài đặt Nginx Ingress Controller cho Kubernetes bằng helm]]></title><description><![CDATA[<p>Ingress là một resource của Kubernetes tương tự như các resource như Deployment, Statefulset,...</p><p>Ingress có nhiệm vụ giúp định tuyến (route) các request từ người dùng bên ngoài vào service được triển khai trong cụm Kubernetes. Thông thường, Ingress được sử dụng với mục đích routing tại layer 7</p>]]></description><link>http://engineering.bizflycloud.vn/cai-dat-nginx-ingress-controller-cho-kubernetes/</link><guid isPermaLink="false">5f81d683f35551008215fb1b</guid><category><![CDATA[blog]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Sa Pham]]></dc:creator><pubDate>Sat, 10 Oct 2020 17:34:35 GMT</pubDate><content:encoded><![CDATA[<p>Ingress là một resource của Kubernetes tương tự như các resource như Deployment, Statefulset,...</p><p>Ingress có nhiệm vụ giúp định tuyến (route) các request từ người dùng bên ngoài vào service được triển khai trong cụm Kubernetes. Thông thường, Ingress được sử dụng với mục đích routing tại layer 7 với các phương thức cơ bản như </p><p>- host-based routing: định tuyến dựa trên hostname truy cập của người dùng. Ví dụ request vào URL https://auth.example.com request sẽ được gửi tới Service Name <strong>production-auth. </strong>Với request vào URL https://api.example.com request sẽ được gửi tới Service Name <strong>production-api</strong></p><p>- path-based routing: định tuyến dựa trên path của request. Ví dụ request vào URL https://api.example.com/user sẽ gửi tới Service Name <strong>production-user-api, </strong>request vào URL https://api.example.com/posts sẽ gửi tới Service Name <strong>production-post-api.</strong></p><p>Trong môi trường microservices, một hệ thống sẽ bao gồm nhiều dịch vụ khác nhau. Do vậy việc sử dụng Ingress để định tuyến tại layer 7 và quản lý các request vào các service đơn giản hơn và linh hoạt hơn. </p><p>Ngoài tính năng cơ bản trên, Ingress Controller còn hỗ trợ nhiều tính năng khác như Rate Limit, Authentication, CORS,... Việc hỗ trợ các tính năng này hoàn toàn phụ thuộc vào Ingress Controller mà bạn sử dụng. Hiện tại có rất nhiều các loại Ingress Controller khác nhau như: Nginx Ingress, Kong Ingress, Traefik, Haproxy Ingress, Voyager, Contour, Istio, Ambassador, Gloo, Skipper. Bạn có thể tham khảo thêm tại [1]</p><p>Trong bài này tôi sẽ cài đặt  Nginx Ingress Controller bằng helm và một vài thiết lập Ingress  cơ bản.</p><p>Thông thường, tôi sẽ cài đặt Ingress Controller ở mode DaemonSet. Lúc này các Ingress Controller cụ thể là Nginx sẽ chạy trên toàn bộ worker nodes. Ta có thể sử dụng Load Balancer để phân tải xuống các Nginx trên các worker node. Điều này giúp ta dễ dàng mở rộng hệ thống khi số lượng request lớn lên. Khi ta thêm các worker node, Nginx Ingress Controller cũng được scale tương ứng.</p><p>Mô hình lý tưởng là User -&gt; L4LB -&gt; L7LB -&gt; Service mô tả như sau</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image.png" class="kg-image"></figure><p></p><p>Khi cài đặt Nginx Ingress Controller, ta thường tạo Service resource cho Ingress. Trên hạ tầng các nhà cung cấp Cloud sẽ khởi tạo Load Balancer và tự động cấu hình forward request port 80 và 443 vào các Nginx Ingress Controller.</p><p>Tôi sẽ sử dụng Cluster Kubernetes tạo sẵn trên hệ thống BizFly Cloud để cài đặt. </p><p>Yêu cầu cài đặt helm version 2 hoặc 3.</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-2.png" class="kg-image"></figure><p></p><p>Thêm repo helm của nginx-ingress </p><!--kg-card-begin: markdown--><pre><code>helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo add stable https://kubernetes-charts.storage.googleapis.com/
helm repo update
</code></pre>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-3.png" class="kg-image"></figure><p>Install Nginx Ingress bằng 1 lệnh duy nhất</p><!--kg-card-begin: markdown--><pre><code>helm install --name nginx ingress-nginx/ingress-nginx --set controller.kind=DaemonSet
</code></pre>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-5.png" class="kg-image"></figure><p>Kiểm tra các pod của nginx-controller</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-6.png" class="kg-image"></figure><p></p><p>Load Balancer đang được khởi tạo</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-7.png" class="kg-image"></figure><p>Sau khi Load Balancer khởi tạo thành công, ta có thể kiểm tra địa chỉ IP External (Public IP) của Load Balancer để truy cập</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-8.png" class="kg-image"></figure><p>Truy cập thử vào Load Balancer</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-10.png" class="kg-image"></figure><p>Kiểm tra Load Balancer trên Dashboard BizFly Cloud</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-11.png" class="kg-image"></figure><p></p><p>Load Balancer được tạo ra với 2 Listener trên port 80 và 443 tương ứng với Nhóm Server như hình sau</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/10/image-12.png" class="kg-image"></figure><p></p><p>Như vậy ta đã cài đặt xong Nginx Ingress Controller ở mode DaemonSet và sử dụng Load Balancer tự động cân tải cho các Nginx process trên các Node worker.</p><p>Trong bài tiếp theo, tôi sẽ hướng dẫn một số cấu hình cơ bản cho Nginx Ingress .</p><p></p><p><strong>References:</strong></p><p>[1] - <a href="https://medium.com/flant-com/comparing-ingress-controllers-for-kubernetes-9b397483b46b">https://medium.com/flant-com/comparing-ingress-controllers-for-kubernetes-9b397483b46b</a></p><p> </p>]]></content:encoded></item><item><title><![CDATA[Kết nối mạng trong Virtual Kubelet (Openstack Zun)]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiu">Giới thiệu</h1>
<p>Như đã nói trong bài viết trước, các pods (capsule) được tạo K8S tạo trên Virtual Kubelet không sử dụng mạng của K8S mà sử dụng mạng của Neutron với project được khai báo biến môi trường.</p>
<p>Thế nên, những pod (capsule) đó hoàn toàn có thể kết</p>]]></description><link>http://engineering.bizflycloud.vn/ket-noi-mang-giua-cac-pod/</link><guid isPermaLink="false">5f5eee30f35551008215faa0</guid><category><![CDATA[blog]]></category><category><![CDATA[kubernetes]]></category><category><![CDATA[openstack]]></category><dc:creator><![CDATA[Lê Minh Quân]]></dc:creator><pubDate>Mon, 14 Sep 2020 05:08:18 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="giithiu">Giới thiệu</h1>
<p>Như đã nói trong bài viết trước, các pods (capsule) được tạo K8S tạo trên Virtual Kubelet không sử dụng mạng của K8S mà sử dụng mạng của Neutron với project được khai báo biến môi trường.</p>
<p>Thế nên, những pod (capsule) đó hoàn toàn có thể kết nối mạng với các VM được tạo bởi Openstack.</p>
<p>Thế nhưng như ta đã biết, ta cũng cần phải có node kubernetes master để schedule vào VK. Vậy trong trường hợp ta muốn sử dụng hệ thống mà pod vừa được tạo trên node K8S, vừa được tạo trên VK (node Compute Openstack), ta sẽ cần thêm hỗ trợ từ Kuryr-Kubernetes (<a href="https://docs.openstack.org/kuryr-kubernetes/latest/">https://docs.openstack.org/kuryr-kubernetes/latest/</a>)</p>
<h2 id="kuryrkubernetes">Kuryr-Kubernetes</h2>
<p>Kuryr-kubernetes cho phép cụm K8S sử dụng mạng của Neutron, từ đó các pod có thể thông mạng với VM và các capsule.</p>
<p>Cài đặt: <a href="https://docs.openstack.org/kuryr-kubernetes/latest/installation/index.html">https://docs.openstack.org/kuryr-kubernetes/latest/installation/index.html</a></p>
<p>Để thử nghiệm ta labs sử dụng mô hình như sau:</p>
<h3 id="mhnh">Mô hình</h3>
<p><img src="https://raw.githubusercontent.com/lmq1999/123/master/BizFly-kubernetes.png" alt="demo"></p>
<p>Mô tả:</p>
<p>VM/Pod gắn vào mạng nào thì sử dụng mạng đó.</p>
<p>VM/Pod đứng cùng hàng dọc với node nào thì được tạo trên node đó.</p>
<p>Nét liền là mạng vật lý.</p>
<p>Nét đứt là mạng tạo bởi neutron.</p>
<h3 id="cctrnghplabs">Các trường hợp labs</h3>
<p>Ta có sử dụng 4 trường hợp kết nối sau:</p>
<ul>
<li>
<p>VM (node2) và pod_VK(node1)</p>
</li>
<li>
<p>pod_VK(node1) và pod_VK(node2)</p>
</li>
<li>
<p>pod_kubelet và VM</p>
</li>
<li>
<p>pod_VK và pod_kubelợp</p>
</li>
</ul>
<h4 id="ktni2podvktrn2nodecomputekhcnhau">Kết nối 2 pod VK trên 2 node compute khác nhau</h4>
<p>Ta triển khai 2 pod_VK trên 2 node compute.</p>
<p>Pod_VK được tạo bởi containerd chứ không phải docker thế nên cần cri-tools để truy cập được vào pod.</p>
<p>cri-tools: <a href="https://github.com/kubernetes-sigs/cri-tools">https://github.com/kubernetes-sigs/cri-tools</a></p>
<p>Đồng thời từ node pod ở node này ta ping thử sang pod ở node còn lại</p>
<pre><code class="language-sh">root@worker1:~# crictl -r unix:///var/run/containerd/containerd.sock ps
CONTAINER           IMAGE               CREATED             STATE               NAME                                                                      ATTEMPT             POD ID
ca91b2afea795       nginx:1.14.2        31 minutes ago      Running             capsule-default-nginx-deployment-virtual-admin-77cf5845f5-mq59d-zeta-11   0                   e9ba6b9769a3a
root@worker1:~# crictl -r unix:///var/run/containerd/containerd.sock exec -it ca91b2afea795 sh
# ping ^C
# ifconfig
eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1450
        inet 10.10.10.56  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::f816:3eff:fea7:cd10  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether fa:16:3e:a7:cd:10  txqueuelen 1000  (Ethernet)
        RX packets 16305  bytes 27046669 (25.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 9296  bytes 634907 (620.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73&lt;UP,LOOPBACK,RUNNING&gt;  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10&lt;host&gt;
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# ping 10.10.10.27
PING 10.10.10.27 (10.10.10.27) 56(84) bytes of data.
64 bytes from 10.10.10.27: icmp_seq=1 ttl=64 time=16.5 ms
64 bytes from 10.10.10.27: icmp_seq=2 ttl=64 time=1.38 ms
64 bytes from 10.10.10.27: icmp_seq=3 ttl=64 time=1.98 ms
64 bytes from 10.10.10.27: icmp_seq=4 ttl=64 time=1.03 ms
^C
--- 10.10.10.27 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 1.038/5.245/16.573/6.549 ms
</code></pre>
<pre><code class="language-sh">root@worker2:~# crictl -r unix:///var/run/containerd/containerd.sock ps
CONTAINER           IMAGE               CREATED             STATE               NAME                                                                      ATTEMPT             POD ID
7a296ffcf7ee6       nginx:1.14.2        41 minutes ago      Running             capsule-default-nginx-deployment-virtual-slef-77cf5845f5-kmrg8-theta-20   0                   2e9d3b1ffe1df
root@worker2:~# crictl -r unix:///var/run/containerd/containerd.sock exec -it 7a296ffcf7ee6 sh
# ifconfig
eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1450
        inet 10.10.10.27  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::f816:3eff:feba:2965  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether fa:16:3e:ba:29:65  txqueuelen 1000  (Ethernet)
        RX packets 17151  bytes 27108767 (25.8 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 9415  bytes 643452 (628.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73&lt;UP,LOOPBACK,RUNNING&gt;  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10&lt;host&gt;
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# ping 10.10.10.56
PING 10.10.10.56 (10.10.10.56) 56(84) bytes of data.
64 bytes from 10.10.10.56: icmp_seq=1 ttl=64 time=2.60 ms
64 bytes from 10.10.10.56: icmp_seq=2 ttl=64 time=1.01 ms
64 bytes from 10.10.10.56: icmp_seq=3 ttl=64 time=0.985 ms
64 bytes from 10.10.10.56: icmp_seq=4 ttl=64 time=1.16 ms
c^C
--- 10.10.10.56 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 0.985/1.442/2.607/0.676 ms
#
</code></pre>
<p>Ta có thể thấy cả 2 chiều đều thông mạng với nhau.</p>
<h4 id="ktnigiapodvkvvmtrn2nodecomputekhcnhau">Kết nối giữa pod VK và VM trên 2 node compute khác nhau</h4>
<p>Ta sang node compute2 console vào VM vừa tạo và ping thử đến pod ở node compute1.</p>
<pre><code class="language-sh">root@worker2:~# virsh console instance-00000006
Connected to domain instance-00000006
Escape character is ^]

login as 'cirros' user. default password: 'gocubsgo'. use 'sudo' for root.
selfservice-instance2c login: cirros
Password:
$ ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
$ ping 10.10.10.56
PING 10.10.10.56 (10.10.10.56): 56 data bytes
64 bytes from 10.10.10.56: seq=0 ttl=64 time=3.432 ms
64 bytes from 10.10.10.56: seq=1 ttl=64 time=0.831 ms
64 bytes from 10.10.10.56: seq=2 ttl=64 time=1.151 ms
64 bytes from 10.10.10.56: seq=3 ttl=64 time=1.970 ms
^C
--- 10.10.10.56 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.831/1.846/3.432 ms
$ ifconfig
eth0      Link encap:Ethernet  HWaddr FA:16:3E:D2:28:E5  
          inet addr:10.10.10.245  Bcast:10.10.10.255  Mask:255.255.255.0
          inet6 addr: fe80::f816:3eff:fed2:28e5/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
          RX packets:276 errors:0 dropped:0 overruns:0 frame:0
          TX packets:139 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:23530 (22.9 KiB)  TX bytes:13196 (12.8 KiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

$
</code></pre>
<p>Ở pod trong node compute1 ta cũng ping thử lại với VM ở node compute2</p>
<pre><code class="language-sh"># ping 10.10.10.245
PING 10.10.10.245 (10.10.10.245) 56(84) bytes of data.
64 bytes from 10.10.10.245: icmp_seq=1 ttl=64 time=2.16 ms
64 bytes from 10.10.10.245: icmp_seq=2 ttl=64 time=0.965 ms
64 bytes from 10.10.10.245: icmp_seq=3 ttl=64 time=1.14 ms
64 bytes from 10.10.10.245: icmp_seq=4 ttl=64 time=1.93 ms
^C
--- 10.10.10.245 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 0.965/1.552/2.167/0.510 ms
# ifconfig
eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1450
        inet 10.10.10.56  netmask 255.255.255.0  broadcast 0.0.0.0
        inet6 fe80::f816:3eff:fea7:cd10  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether fa:16:3e:a7:cd:10  txqueuelen 1000  (Ethernet)
        RX packets 16331  bytes 27048713 (25.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 9322  bytes 636951 (622.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73&lt;UP,LOOPBACK,RUNNING&gt;  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10&lt;host&gt;
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
</code></pre>
<p>Ta có thể thấy giữa VM và pod cũng thông mạng với nhau.</p>
<h4 id="ktnigiapodkubeletvvm">Kết nối giữa pod-kubelet và VM</h4>
<p>Với kuryr-kubernetes, ta có thể cho pod sử dụng cùng mạng với mạng được tạo bởi openstack neutron.</p>
<p>Ta thử ping đến pod từ VM</p>
<pre><code class="language-sh">$ ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether fa:16:3e:5c:0e:b1 brd ff:ff:ff:ff:ff:ff
    inet 10.1.3.117/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe5c:eb1/64 scope link
       valid_lft forever preferred_lft forever
$ ping 10.1.2.67
PING 10.1.2.67 (10.1.2.67): 56 data bytes
64 bytes from 10.1.2.67: seq=0 ttl=64 time=4.967 ms
64 bytes from 10.1.2.67: seq=1 ttl=64 time=1.675 ms
64 bytes from 10.1.2.67: seq=2 ttl=64 time=1.086 ms
64 bytes from 10.1.2.67: seq=3 ttl=64 time=2.049 ms
^C
--- 10.1.2.67 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 1.086/2.444/4.967 ms
</code></pre>
<p>Ta tạo 1 pod mới sử dụng image cirros</p>
<pre><code class="language-sh">root@k8s-master:~# kubectl get pod -o wide
NAME                                             READY   STATUS    RESTARTS   AGE     IP            NODE              NOMINATED NODE   READINESS GATES
cirros-deployment-worker-75ffdf847-vrds7         1/1     Running   0          3m58s   10.1.2.87     k8s-worker        &lt;none&gt;           &lt;none&gt;
nginx-deployment-virtual-slef-77cf5845f5-kmrg8   1/1     Running   0          3h24m   10.10.10.27   virtual-kubelet   &lt;none&gt;           &lt;none&gt;
nginx-deployment-worker-57d9684bf8-gsfth         1/1     Running   0          50m     10.1.2.67     k8s-worker        &lt;none&gt;           &lt;none&gt;
</code></pre>
<p>Ta truy cập vào pod và ping thử lại VM</p>
<pre><code class="language-sh">root@k8s-master:~# kubectl exec -it cirros-deployment-worker-75ffdf847-vrds7  sh
/ # ping 10.1.3.117
PING 10.1.3.117 (10.1.3.117): 56 data bytes
64 bytes from 10.1.3.117: seq=0 ttl=64 time=2.982 ms
64 bytes from 10.1.3.117: seq=1 ttl=64 time=1.540 ms
64 bytes from 10.1.3.117: seq=2 ttl=64 time=1.011 ms
64 bytes from 10.1.3.117: seq=3 ttl=64 time=0.827 ms
^C
--- 10.1.3.117 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.827/1.590/2.982 ms
/ # ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
3: eth0@if21: &lt;BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN&gt; mtu 1450 qdisc noqueue qlen 1000
    link/ether fa:16:3e:86:63:29 brd ff:ff:ff:ff:ff:ff
    inet 10.1.2.87/16 scope global eth0
       valid_lft forever preferred_lft forever
/ #
</code></pre>
<p>Ta có thể thấy pod tạo bơi kubelet và VM thông với nhau.</p>
<h4 id="ktnigiapodtobikubeletvvirtualkubelet">Kết nối giữa pod tạo bởi kubelet và virtual kubelet</h4>
<p>Ta tạo 1 pod (VK) trên dải mạng của cho pod của kubernetes</p>
<pre><code class="language-sh">root@k8s-master:~# kubectl get pod -o wide
NAME                                              READY   STATUS    RESTARTS   AGE     IP            NODE              NOMINATED NODE   READINESS GATES
cirros-deployment-worker-75ffdf847-vrds7          1/1     Running   0          29m     10.1.2.87     k8s-worker        &lt;none&gt;           &lt;none&gt;
nginx-deployment-virtual-admin-77cf5845f5-5dg2v   1/1     Running   0          9m55s   10.1.1.173    virtual-kubelet   &lt;none&gt;           &lt;none&gt;
nginx-deployment-virtual-slef-77cf5845f5-kmrg8    1/1     Running   0          3h50m   10.10.10.27   virtual-kubelet   &lt;none&gt;           &lt;none&gt;
nginx-deployment-worker-57d9684bf8-gsfth          1/1     Running   0          76m     10.1.2.67     k8s-worker        &lt;none&gt;           &lt;none&gt;
</code></pre>
<p>Ta truy cập vào node compute2, truy cập vào pod</p>
<pre><code class="language-sh"># ifconfig
eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1450
        inet 10.1.1.173  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::f816:3eff:fec1:1b68  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether fa:16:3e:c1:1b:68  txqueuelen 1000  (Ethernet)
        RX packets 10399  bytes 16046109 (15.3 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 6207  bytes 446993 (436.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73&lt;UP,LOOPBACK,RUNNING&gt;  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10&lt;host&gt;
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# ping 10.1.2.87
PING 10.1.2.87 (10.1.2.87) 56(84) bytes of data.
64 bytes from 10.1.2.87: icmp_seq=1 ttl=64 time=3.71 ms
64 bytes from 10.1.2.87: icmp_seq=2 ttl=64 time=1.25 ms
64 bytes from 10.1.2.87: icmp_seq=3 ttl=64 time=0.795 ms
64 bytes from 10.1.2.87: icmp_seq=4 ttl=64 time=1.21 ms
^C
--- 10.1.2.87 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3017ms
rtt min/avg/max/mdev = 0.795/1.743/3.710/1.150 ms
#
# ping 10.1.2.67
PING 10.1.2.67 (10.1.2.67) 56(84) bytes of data.
64 bytes from 10.1.2.67: icmp_seq=1 ttl=64 time=1.62 ms
64 bytes from 10.1.2.67: icmp_seq=2 ttl=64 time=1.03 ms
64 bytes from 10.1.2.67: icmp_seq=3 ttl=64 time=1.63 ms
64 bytes from 10.1.2.67: icmp_seq=4 ttl=64 time=1.52 ms
^C
--- 10.1.2.67 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 1.032/1.454/1.635/0.252 ms
#
</code></pre>
<p>Ta có thấy được từ pod tạo bởi (VK) cũng thông mạng đến pod tạo bởi kubelet thường.</p>
<h3 id="openstackloadbalancerctokhiexposeservice">Openstack Loadbalancer được tạo khi expose service</h3>
<p>Như sơ đồ ở trên, ta thấy rằng k có pod/VM nào sử dụng dải service, dải đó dành riêng cho những loadbalancer (Openstack Octavia) dùng cho service của Kubernetes.</p>
<p>Khi ta expose service</p>
<pre><code class="language-sh">root@k8s-master:~# kubectl get pod -o wide
NAME                                              READY   STATUS    RESTARTS   AGE    IP            NODE              NOMINATED NODE   READINESS GATES
cirros-deployment-worker-75ffdf847-vrds7          1/1     Running   0          43m    10.1.2.87     k8s-worker        &lt;none&gt;           &lt;none&gt;
nginx-deployment-virtual-admin-77cf5845f5-5dg2v   1/1     Running   0          23m    10.1.1.173    virtual-kubelet   &lt;none&gt;           &lt;none&gt;
nginx-deployment-virtual-slef-77cf5845f5-kmrg8    1/1     Running   0          4h3m   10.10.10.27   virtual-kubelet   &lt;none&gt;           &lt;none&gt;
nginx-deployment-worker-57d9684bf8-gsfth          1/1     Running   0          89m    10.1.2.67     k8s-worker        &lt;none&gt;           &lt;none&gt;
root@k8s-master:~# kubectl expose deployment nginx-deployment-
nginx-deployment-virtual-admin  nginx-deployment-virtual-slef   nginx-deployment-worker
root@k8s-master:~# kubectl expose deployment nginx-deployment-worker
service/nginx-deployment-worker exposed
root@k8s-master:~# kubectl get svc
NAME                             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes                       ClusterIP   10.2.0.1       &lt;none&gt;        443/TCP   4h44m
nginx-deployment-virtual-admin   ClusterIP   10.2.154.91    &lt;none&gt;        80/TCP    24s
nginx-deployment-worker          ClusterIP   10.2.182.210   &lt;none&gt;        80/TCP    3s
root@k8s-master:~# kubectl edit svc nginx-deployment-worker
service/nginx-deployment-worker edited
root@k8s-master:~# kubectl edit svc nginx-deployment-virtual-admin
service/nginx-deployment-virtual-admin edited
root@k8s-master:~# kubectl get svc
NAME                             TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes                       ClusterIP      10.2.0.1       &lt;none&gt;        443/TCP        4h48m
nginx-deployment-virtual-admin   LoadBalancer   10.2.154.91    &lt;pending&gt;     80:31012/TCP   4m22s
nginx-deployment-worker          LoadBalancer   10.2.182.210   &lt;pending&gt;     80:30066/TCP   4m1s

</code></pre>
<p>Loadbalancer được tạo và gọi đến</p>
<pre><code>[root@controller ~(kubernetes)]$ openstack loadbalancer list
+--------------------------------------+----------------------------------------+----------------------------------+--------------+---------------------+----------+
| id                                   | name                                   | project_id                       | vip_address  | provisioning_status | provider |
+--------------------------------------+----------------------------------------+----------------------------------+--------------+---------------------+----------+
| 96be6376-3eed-4822-a3e1-9deba4b37918 | kube-system/kube-dns                   | 623f7793c0974c50a932c4e6b7145b95 | 10.2.0.10    | PENDING_CREATE      | amphora  |
| 879c7bd0-43d5-41c3-9868-c9cfd5168687 | default/nginx-deployment-virtual-admin | 623f7793c0974c50a932c4e6b7145b95 | 10.2.154.91  | ACTIVE              | amphora  |
| 8733211d-9c49-40e5-8952-180aa7621bde | default/nginx-deployment-worker        | 623f7793c0974c50a932c4e6b7145b95 | 10.2.182.210 | PENDING_UPDATE      | amphora  |
+--------------------------------------+----------------------------------------+----------------------------------+--------------+---------------------+----------+
[root@controller ~(kubernetes)]$ curl 10.2.154.91
^Ccu


[root@controller ~(kubernetes)]$ cu
^C
[root@controller ~(kubernetes)]$ curl 10.2.154.91
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Welcome to nginx!&lt;/title&gt;
&lt;style&gt;
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Welcome to nginx!&lt;/h1&gt;
&lt;p&gt;If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.&lt;/p&gt;

&lt;p&gt;For online documentation and support please refer to
&lt;a href=&quot;http://nginx.org/&quot;&gt;nginx.org&lt;/a&gt;.&lt;br/&gt;
Commercial support is available at
&lt;a href=&quot;http://nginx.com/&quot;&gt;nginx.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thank you for using nginx.&lt;/em&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
[root@controller ~(kubernetes)]$ curl 10.2.182.210
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Welcome to nginx!&lt;/title&gt;
&lt;style&gt;
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Welcome to nginx!&lt;/h1&gt;
&lt;p&gt;If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.&lt;/p&gt;

&lt;p&gt;For online documentation and support please refer to
&lt;a href=&quot;http://nginx.org/&quot;&gt;nginx.org&lt;/a&gt;.&lt;br/&gt;
Commercial support is available at
&lt;a href=&quot;http://nginx.com/&quot;&gt;nginx.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thank you for using nginx.&lt;/em&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h2 id="ktlun">Kết luận</h2>
<p>Vậy với Openstack Zun và Kuryr-Kubernetes, ta có thể có 1 hệ thống Cloud Openstack kết hợp với K8S và cả Nodeless</p>
<!--kg-card-end: markdown--><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[GIới thiệu về Virtual Kubelet]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="giithiu">Giới thiệu</h2>
<p>Virutal kubelet (VK) là triển khai mã nguồn mở của Kubernetes Kubelet làm 1 Kubelet nhằm mục đích kết nối Kubernetes đến các APIs khác.</p>
<p>Mô hình:</p>
<p><img src="https://raw.githubusercontent.com/virtual-kubelet/virtual-kubelet/master/website/static/img/diagram.svg" alt="VK"></p>
<p>Vì Virtual Kubelet không thực sự là 1 node kubelet thế nên các containers/pod sẽ được tạo thực tế ở</p>]]></description><link>http://engineering.bizflycloud.vn/virtual-kubelet/</link><guid isPermaLink="false">5f5eea2ef35551008215fa86</guid><category><![CDATA[blog]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Lê Minh Quân]]></dc:creator><pubDate>Mon, 14 Sep 2020 04:04:37 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="giithiu">Giới thiệu</h2>
<p>Virutal kubelet (VK) là triển khai mã nguồn mở của Kubernetes Kubelet làm 1 Kubelet nhằm mục đích kết nối Kubernetes đến các APIs khác.</p>
<p>Mô hình:</p>
<p><img src="https://raw.githubusercontent.com/virtual-kubelet/virtual-kubelet/master/website/static/img/diagram.svg" alt="VK"></p>
<p>Vì Virtual Kubelet không thực sự là 1 node kubelet thế nên các containers/pod sẽ được tạo thực tế ở trên các cloud providers khác cung cấp dịch vụ.</p>
<p>Các providers đang hỗ trợ:</p>
<pre><code class="language-sh">Admiralty Multi-Cluster Scheduler
Alibaba Cloud Elastic Container Instance (ECI)
AWS Fargate
Azure Batch
Azure Container Instances (ACI)
Elotl Kip
Kubernetes Container Runtime Interface (CRI)
Huawei Cloud Container Instance (CCI)
HashiCorp Nomad
OpenStack Zun
Tencent Games Tensile Kube
</code></pre>
<p>Ở đây chúng ta sẽ sử dụng openstack zun</p>
<h2 id="cit">Cài đặt</h2>
<p>Để cài đăt, ta cần cài đặt Go và đặt biến môi trường GOPATH (tham khảo tại): <code>https://www.linode.com/docs/development/go/install-go-on-ubuntu/</code></p>
<p>Tải VK về từ github: <code>https://github.com/virtual-kubelet/openstack-zun.git</code></p>
<p>Truy cập đến thư mục: <code>~/openstack-zun/cmd/virtual-kubelet#</code></p>
<p>Sau đó build: <code>go build main.go</code></p>
<p>đổi tên <code>main</code> -&gt; <code>virtual-kubelet</code> copy vào thư mục <code>/usr/bin</code></p>
<h2 id="khichy">Khởi chạy</h2>
<p>Để khởi chạy ta cần xác thực qua keystone, ta cần những biến môi trường như sau:</p>
<pre><code class="language-sh">export OS_DOMAIN_ID=default
export OS_REGION_NAME=RegionOne
export OS_PROJECT_NAME=demo
export OS_IDENTITY_API_VERSION=3
export OS_AUTH_URL=http://10.0.2.15/identity/v3
export OS_USERNAME=demo
export OS_PASSWORD=password
</code></pre>
<p>P/s: đặt biến môi trường theo cài đặt của mình</p>
<p>Sau đó chạy lệnh <code>virtual-kubelet</code></p>
<p>Kết quả:</p>
<pre><code class="language-sh">root@k8s-master:~# kubectl get nodes
NAME              STATUS   ROLES    AGE    VERSION
k8s-master        Ready    master   122m   v1.13.3
k8s-worker        Ready    &lt;none&gt;   105m   v1.13.3
virtual-kubelet   Ready    agent    94m    v1.14.3
</code></pre>
<p>Triển khai pods trong VK:</p>
<p>Vì OpenStack virtual node được cấp 1 taint, thế nên cần toleration để triển khai pod đó:</p>
<pre><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  tolerations:
  - key: &quot;virtual-kubelet.io/provider&quot;
    operator: &quot;Equal&quot;
    value: &quot;openstack&quot;
    effect: &quot;NoSchedule&quot;
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! &amp;&amp; sleep 3600']

</code></pre>
<pre><code class="language-sh">root@k8s-master:~# kubectl get pod -o wide
NAME                                        READY   STATUS        RESTARTS   AGE   IP           NODE              NOMINATED NODE   READINESS GATES
nginx-deployment-virtual-77cf5845f5-8h9tp   1/1     Running       0          14m   10.1.1.54    k8s-worker        &lt;none&gt;           &lt;none&gt;
nginx-deployment-worker-57d9684bf8-z7skz    1/1     Running       1          51m   10.1.1.191   k8s-worker        &lt;none&gt;           &lt;none&gt;

</code></pre>
<p>Check trên openstack:</p>
<pre><code class="language-sh">openstack capsule list
+--------------------------------------+---------------------------------------------------+---------+------------+
| uuid                                 | name                                              | status  | addresses  |
+--------------------------------------+---------------------------------------------------+---------+------------+
| 4fe2d632-cb11-4596-b9a9-feebab10191f | default-nginx-deployment-virtual-77cf5845f5-npxcv | Running | 10.1.0.198 |
| 3ff4a995-67c0-416d-bced-78378c6f616e | kube-system-kube-proxy-4jt8p                      | Error   |            |
+--------------------------------------+---------------------------------------------------+---------+------------+
</code></pre>
<p>Chú ý, vì VK không sử dụng mạng của k8s tạo ra mà dụng mạng của neutron nên kube-proxy lỗi là điều bình thường.</p>
<p>Đối với Openstack Zun, có 2 khái niệm cần để ý đó là containers và capsule.<br>
Capsule tương ứng với pod và containers tương ứng với containers</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Auto-scale Kubernetes pod với custom metrics cho MQTT broker]]></title><description><![CDATA[<p></p><p>Như ta đã biết, Kubernetes sử dụng Horizontal Pod Autoscaler (HPA) để có thể scale số lượng pod. </p><p>Để có thể làm được điều đó, HPA sẽ thực hiện vòng loop để query những metrics hiện tại sau đó tính toán và thực viện công việc scale.</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/07/image.png" class="kg-image"></figure><p>Nhưng có vấn</p>]]></description><link>http://engineering.bizflycloud.vn/auto-scale-kubernetes-pod-voi-custom-metrics/</link><guid isPermaLink="false">5f193fc1f35551008215f924</guid><category><![CDATA[blog]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Lê Minh Quân]]></dc:creator><pubDate>Fri, 24 Jul 2020 09:08:53 GMT</pubDate><content:encoded><![CDATA[<p></p><p>Như ta đã biết, Kubernetes sử dụng Horizontal Pod Autoscaler (HPA) để có thể scale số lượng pod. </p><p>Để có thể làm được điều đó, HPA sẽ thực hiện vòng loop để query những metrics hiện tại sau đó tính toán và thực viện công việc scale.</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/07/image.png" class="kg-image"></figure><p>Nhưng có vấn đề đặt ra ở đây, đó là đôi khi những metrics thu về được lại chưa đủ để có thể thực hiện scale. Ví dụ sẽ được nói đến tiếp theo trong bài viết.</p><p>Để thực hiện điều này thì Kubernetes có thành phần được gọi<em> metrics registry. </em>Mục đích <em>metrics registry </em>là cung cấp giao diện để client có thể query metrics. Giao diện này gồm 3 thành phần là:</p><ul><li><strong>Resource Metrics API</strong></li><li><strong>Custom Metrics API</strong></li><li><strong>External Metrics API</strong></li></ul><p>Vậy khi chúng ta muốn scale với <strong>Custom Metrics API</strong>, ta cần phải cung cấp backend cho nó. Backend này bao gồm 2 thành phần chính đó là <em>Metric collector </em>và <em>Metric API server.</em></p><p><strong>METRIC COLLECTOR</strong>  </p><p>Chúng ta sẽ lựa chọn <em>Metric collector </em>khá phổ biến: <em>Prometheus</em></p><p>Để cho đơn giản,ở đây ta sẽ sử dụng <em>Prometheus-operator </em>thông qua<em> Helm:</em><br><br>Repo prometheus-operator:</p><p><a href="https://github.com/helm/charts/tree/master/stable/prometheus-operator">https://github.com/helm/charts/tree/master/stable/prometheus-operator</a></p><p>Prometheus-operator gồm nhiều thành phần, trong đó chủ yếu là Prometheus, Grafana (công cụ tạo dashboard), và các service monitor để lấy metrics từ kubernetes.</p><p>Câu lệnh: </p><!--kg-card-begin: markdown--><p><code>helm install my-mon stable/prometheus-operator -f values.yaml</code></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Trong đó <code>values.yaml</code> là file mình tự tạo với nội dung như sau:</p>
<p><code>serviceMonitorSelectorNilUsesHelmValues: false</code> [1]</p>
<p>Việc này là cần thiết vì nó sẽ cho phép thu được những metrics khác ngoài những thành phần của Kubernetes.</p>
<!--kg-card-end: markdown--><p>Sau khi thực hiện xong, ta hoàn toàn có thể truy cập trang web đã được host lên:<br></p><p><u>Prometheus:</u></p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/07/image-1.png" class="kg-image"></figure><p>Grafana:<br></p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/07/image-3.png" class="kg-image"></figure><p></p><p><strong>MQTT BROKER (VerneMQ)</strong></p><p>Ta sẽ sử dụng VerneMQ làm MQTT Broker làm ví dụ</p><p>Tiếp tục sử dụng Helm để tải VerneMQ<br><br>Repo: </p><pre><code>https://vernemq.github.io/docker-vernemq</code></pre><p>Ta cần phải cấu hình VerneMQ 1 chút mới có thể chạy được không như Prometheus-operator.</p><p>Đầu tiên, ta cần pull verneMQ chart về:</p><!--kg-card-begin: markdown--><p><code>helm pull vernemq/vernemq --untar true</code></p>
<p>Ta sẽ pull Chart về và giải nén, ta có thư mục <code>vernemq</code></p>
<p>Truy cập file <code>values.yaml</code> trong thư mục, ta chỉnh sửa 1 số thông số như sau</p>
<p><strong>Quan trọng</strong></p>
<p>Vì helm sử dụng <code>image 1.10.2</code> để tạo vernemq và image này bị lỗi thiếu thư viện, ta cần chỉnh config</p>
<p><code>image: 1.10.2</code> thành <code>image: 1.10.2-1-alpine</code> hoặc <code>image: lastest</code> để không gặp lỗi này</p>
<p>Sau đó:</p>
<pre><code>serviceMonitor:
  create: true
</code></pre>
<p>Tạo ra service monitor để prometheus lấy được những metrics</p>
<p>Đồng thời ta cần phải thêm vào:</p>
<pre><code>additionalEnv:
  - name: DOCKER_VERNEMQ_ALLOW_ANONYMOUS
    value: &quot;on&quot;
  - name: DOCKER_VERNEMQ_ACCEPT_EULA
    value: &quot;yes&quot;
</code></pre>
<pre><code>  - name: DOCKER_VERNEMQ_ALLOW_ANONYMOUS
    value: &quot;on&quot;
</code></pre>
<p>Để bỏ qua bước xác thực khi truyền tin</p>
<pre><code>  - name: DOCKER_VERNEMQ_ACCEPT_EULA
    value: &quot;yes&quot;
</code></pre>
<p>Chấp nhận điều khoản sử dụng của VerneMQ [2]</p>
<p>Ngoài ra, VerneMQ còn là 1 <em>Stateful Cluster</em> thế nên ta cần phải lệnh gọi để tách node khỏi cluster khi scale down.</p>
<p>Trong thư mục <code>templates</code>, ta truy cập file <code>statefulset.yaml</code> thêm nội dung:</p>
<pre><code>lifecycle:
            preStop:
              exec:
                command: [&quot;/bin/bash&quot;,&quot;-c&quot;,&quot;vmq-admin cluster leave node=VerneMQ@$HOSTNAME.myvernemq-headless.default.svc.cluster.local -k -i 1 -t 30&quot;]
</code></pre>
<p>Sau khi cấu hình xong, ta sử dụng helm để triển khai:</p>
<p><code>helm install myVerneMQ . --set replicaCount=2 -f values.yaml</code></p>
<!--kg-card-end: markdown--><p>Sau khi triển khai xong, thì Prometheus cũng có thể lấy được metrics từ VerneMQ (VerneMQ có exporter mặc định khi được tạo ở port 8888) [3]</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/07/image-4.png" class="kg-image"></figure><p></p><p>Để kiểm tra hoạt động monitor đúng, ta sẽ thử publish message đến</p><p>Ở đây ta sẽ sử dụng Python và thư viện paho-mqtt</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://pypi.org/project/paho-mqtt/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">paho-mqtt</div><div class="kg-bookmark-description">MQTT version 3.1.1 client class</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://pypi.org/static/images/favicon.6a76275d.ico"><span class="kg-bookmark-publisher">PyPI</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://pypi.org/static/images/twitter.90915068.jpg"></div></a></figure><!--kg-card-begin: markdown--><p>Code python:</p>
<pre><code>import paho.mqtt.client as paho
import timebroker=&quot;localhost&quot;
port=1883def on_publish(client,userdata,mid):             #create function for callback
    print(&quot;Published message to topic&quot;,&quot;ecg/omniacare/devices&quot;)
    print(&quot;mid=&quot;, mid)
    passclient1 = paho.Client(&quot;control1&quot;)                           #create client objectclient1.on_publish = on_publish                          #assign function to callbackff = open(&quot;/home/mqtt_ecg.txt&quot;,&quot;r&quot;)
ss = ff.read()

x = 3000
while True:
    x += 1
    client1.connect(broker,port) #establish connection
    client1.loop_start() #start the loop
    ss2 = ss.replace(&quot;mario.rossi&quot;, &quot;mario.rossi.&quot;+str(x).zfill(6))
    print(&quot;Publishing message to topic&quot;,&quot;ecg/omniacare/devices&quot;)
    res = client1.publish(&quot;/ecg/omniacare/devices/0X345000DFG&quot;,ss2,2,0)
    print(&quot;Post publishing message to topic&quot;,&quot;ecg/omniacare/devices&quot;,res)
    client1.loop_stop(force=True)
    client1.disconnect()
    time.sleep(5) # wait
</code></pre>
<p>time.sleep(5) để điều khiển tần suất bắn message</p>
<!--kg-card-end: markdown--><p>Ta sẽ tạo dashboard sử dụng grafana </p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/07/image-5.png" class="kg-image"></figure><p>Trong đó:<br><br></p><!--kg-card-begin: markdown--><p>Total publish receive: <code>sum(mqtt_publish_received)</code></p>
<p>Total publish receive per second: <code>sum(irate(mqtt_publish_received{mqtt_version=&quot;4&quot;}[1m]))</code></p>
<p>Publish receiver per second per node:<br>
<code>irate(mqtt_publish_received{mqtt_version=&quot;4&quot;}[1m])</code></p>
<!--kg-card-end: markdown--><p>Ở đây, ta muốn cho VerneMQ scale theo số lượng message publish mỗi giây, nhưng lại không có metrics nào đáp ứng được nhu cầu của chúng ta cả.</p><p>Và như đã nói ở trên, chúng ta cần <em>Metric collector </em>và <em>Metric API server, </em>ta sẽ cần<em> Metric API server. </em>Ở đây chúng ta sử dụng <em>Prometheus-adapter</em></p><p><strong>METRIC API SERVER</strong></p><p>repo :</p><p><a href="https://github.com/helm/charts/tree/master/stable/prometheus-adapter">https://github.com/helm/charts/tree/master/stable/prometheus-adapter</a></p><p>Tương tự như VerneMQ, ta cũng cần pull về cấu hình 1 số chỗ</p><!--kg-card-begin: markdown--><p>Trong file <code>values.yaml</code></p>
<pre><code># Url to access prometheus
prometheus:
  url: http://my-mon-prometheus-operator-prometheus.default.svc.cluster.local
  port: 9090
</code></pre>
<p>Ta trỏ đến prometheus operator</p>
<pre><code>rules:
    - seriesQuery:
    '{namespace!=&quot;&quot;,__name__=&quot;mqtt_publish_received&quot;,mqtt_version=&quot;4&quot;}'
      seriesFilters: []
      resources:
        template: &lt;&lt;.Resource&gt;&gt;
      metricsQuery: sum(irate(&lt;&lt;.Series&gt;&gt;{&lt;&lt;.LabelMatchers&gt;&gt;}[1m])) by (&lt;&lt;.GroupBy&gt;&gt;)
</code></pre>
<p>Ta tạo custom rule để biến metrics <code>mqtt_publish_received</code> trở thành tổng số message nhận được mỗi giây trên mỗi node <code>sum(irate(&lt;&lt;.Series&gt;&gt;{&lt;&lt;.LabelMatchers&gt;&gt;}[1m])) by (&lt;&lt;.GroupBy&gt;&gt;)</code></p>
<p>Sau đó khởi tạo prometheus-adapter</p>
<p><code>helm install prom-adap . -f values.yaml</code></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="toautoscalevkimtra">Tạo autoscale và kiểm tra</h3>
<pre><code class="language-yaml">apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: vernemq-autoscaler
spec:
  scaleTargetRef:
    # point the HPA at the sample application
    # you created above
    apiVersion: apps/v1
    kind: StatefulSet
    name: myvernemq
  # autoscale between 1 and 10 replicas
  minReplicas: 1
  maxReplicas: 10
  metrics:
  # use a &quot;Pods&quot; metric, which takes the average of the
  # given metric across all pods controlled by the autoscaling target
  - type: Pods
    pods:
      # use the metric that you used above: pods/http_requests
      metricName: mqtt_publish_received
      # target 500 milli-requests per second,
      # which is 1 request every two seconds
      targetAverageValue: 60m
</code></pre>
<p>Ban đầu khi không chạy stress test:</p>
<pre><code class="language-md">NAME                 REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
vernemq-autoscaler   StatefulSet/myvernemq   0/60m     1         10        1          3h49m


+----------------------------------------------------------------+-------+
|                              Node                              |Running|
+----------------------------------------------------------------+-------+
|VerneMQ@myvernemq-0.myvernemq-headless.default.svc.cluster.local| true  |

</code></pre>
<p>Khi tải tăng lên</p>
<pre><code class="language-md">+----------------------------------------------------------------+-------+
|                              Node                              |Running|
+----------------------------------------------------------------+-------+
|VerneMQ@myvernemq-0.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-1.myvernemq-headless.default.svc.cluster.local| true  |
+----------------------------------------------------------------+-------+

vernemq-autoscaler   StatefulSet/myvernemq   22m/60m   1         10        3          3h8m 
NAME                 REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE 
vernemq-autoscaler   StatefulSet/myvernemq   22m/60m   1         10        3          3h8m 
</code></pre>
<p>Tiếp tục tăng:</p>
<pre><code class="language-md">vernemq-autoscaler   StatefulSet/myvernemq   266m/60m   1         10        4          146m
NAME                 REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE 
vernemq-autoscaler   StatefulSet/myvernemq   266m/60m   1         10        4          146m
NAME                 REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE 
vernemq-autoscaler   StatefulSet/myvernemq   266m/60m   1         10        4          146m
NAME                 REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE 
vernemq-autoscaler   StatefulSet/myvernemq   800m/60m   1         10        5          146m


+----------------------------------------------------------------+-------+
|                              Node                              |Running|
+----------------------------------------------------------------+-------+
|VerneMQ@myvernemq-0.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-1.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-2.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-3.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-4.myvernemq-headless.default.svc.cluster.local| true  |
+----------------------------------------------------------------+-------+

</code></pre>
<p>Sau cùng:</p>
<pre><code class="language-md">+----------------------------------------------------------------+-------+
|                              Node                              |Running|
+----------------------------------------------------------------+-------+
|VerneMQ@myvernemq-0.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-1.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-2.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-3.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-4.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-5.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-6.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-7.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-8.myvernemq-headless.default.svc.cluster.local| true  |
|VerneMQ@myvernemq-9.myvernemq-headless.default.svc.cluster.local| true  |
+----------------------------------------------------------------+-------+

NAME                 REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE 
vernemq-autoscaler   StatefulSet/myvernemq   11m/60m   1         10        10         154m 
NAME                 REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE 
vernemq-autoscaler   StatefulSet/myvernemq   22m/60m   1         10        10         154m 
</code></pre>
<p><img src="https://raw.githubusercontent.com/lmq1999/Mytest/master/Screenshot%20from%202020-06-20%2010-00-23.png" alt></p>
<p><img src="https://raw.githubusercontent.com/lmq1999/123/master/Screenshot%20from%202020-06-20%2010-07-46.png" alt></p>
<p><img src="https://raw.githubusercontent.com/lmq1999/Mytest/master/Screenshot%20from%202020-06-20%2010-06-37.png" alt></p>
<p><img src="https://raw.githubusercontent.com/lmq1999/123/master/Screenshot%20from%202020-06-20%2010-33-03.png" alt></p>
<p>Ta theo dõi vào TARGETS có thể thấy pod được scale khi request đến nhiều hơn, và scale vào khi ít request đi.</p>
<!--kg-card-end: markdown--><p>References: </p><p>[1] - <a href="https://github.com/helm/charts/tree/master/stable/prometheus-operator#prometheusioscrape">https://github.com/helm/charts/tree/master/stable/prometheus-operator#prometheusioscrape</a></p><p>[2] - <a href="https://docs.vernemq.com/installation/accepting-the-vernemq-eula">https://docs.vernemq.com/installation/accepting-the-vernemq-eula</a></p><p>[3] - <a href="https://docs.vernemq.com/monitoring/prometheus">https://docs.vernemq.com/monitoring/prometheus</a></p>]]></content:encoded></item><item><title><![CDATA[Public toàn bộ files trong một S3 bucket]]></title><description><![CDATA[<p>Gần đây có nhiều khách hàng sử dụng S3 bên mình và khách hàng đang lầm tưởng rằng việc thực hiện set ACL Public cho bucket thì toàn bộ objects/files trong bucket đó sẽ public theo. </p><p>Bản chất việc thiết lập ACL Public cho 1 Bucket cho phép public</p>]]></description><link>http://engineering.bizflycloud.vn/public-toan-bo-files-trong-mot-s3-bucket/</link><guid isPermaLink="false">5f0b25afac64d40080216a12</guid><category><![CDATA[blog]]></category><category><![CDATA[bizflycloud]]></category><dc:creator><![CDATA[Sa Pham]]></dc:creator><pubDate>Sun, 12 Jul 2020 15:18:36 GMT</pubDate><content:encoded><![CDATA[<p>Gần đây có nhiều khách hàng sử dụng S3 bên mình và khách hàng đang lầm tưởng rằng việc thực hiện set ACL Public cho bucket thì toàn bộ objects/files trong bucket đó sẽ public theo. </p><p>Bản chất việc thiết lập ACL Public cho 1 Bucket cho phép public danh sách các object có trong bucket đó, nên khi người dùng thực hiện truy cập vào một file thì không thể truy cập được và thông báo như sau</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/07/Screenshot-from-2020-07-12-22-10-28.png" class="kg-image"></figure><p>Mặc dù Bucket này đã public như thiết lập sau</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/07/Screenshot-from-2020-07-12-22-11-02.png" class="kg-image"></figure><p>Do vậy, để có thể truy cập vào file trong bucket trên ta có 2 cách</p><p>- Thực hiện set public đối với toàn bộ file khi thực hiện upload</p><p>- Hoặc sử dụng bucket policy để thiết lập bucket.</p><p>Trong bài này, tôi sẽ sử dụng bucket policy để thiết lập public cho toàn bộ file trong bucket.</p><p>Để thực hiện điều này, ta sử dụng lệnh s3cmd. Xem thêm hướng dẫn cấu hình s3cmd tại [1].</p><p></p><p>Tạo file `policy.json` như sau</p><!--kg-card-begin: markdown--><pre><code>{
  &quot;Version&quot;:&quot;2012-10-17&quot;,
  &quot;Statement&quot;:[{
    &quot;Sid&quot;:&quot;AddPerm&quot;,
        &quot;Effect&quot;:&quot;Allow&quot;,
      &quot;Principal&quot;: &quot;*&quot;,
      &quot;Action&quot;:[&quot;s3:GetObject&quot;],
      &quot;Resource&quot;:[&quot;arn:aws:s3:::sapd-test-bucket-private/*&quot;
      ]
    }
  ]
}
</code></pre>
<!--kg-card-end: markdown--><p>Với <strong>sapd-test-bucket-private</strong> đây là tên bucket của bạn, bạn cần thay thế tương ứng với bucket mà bạn muốn public toàn bộ file trong bucket đó.</p><p></p><p>Thiết lập policy cho bucket bằng lệnh sau </p><!--kg-card-begin: markdown--><pre><code>s3cmd setpolicy policy.json s3://sapd-test-bucket-private
</code></pre>
<!--kg-card-end: markdown--><p>Kiểm tra lại thông tin policy</p><!--kg-card-begin: markdown--><pre><code>sapd@sapd ~/WORK/VC/s3 $ s3cmd info s3://sapd-test-bucket-private
s3://sapd-test-bucket-private/ (bucket):
   Location:  hn
   Payer:     BucketOwner
   Expiration Rule: none
   Policy:    b'{\n  &quot;Version&quot;:&quot;2012-10-17&quot;,\n  &quot;Statement&quot;:[{\n    &quot;Sid&quot;:&quot;AddPerm&quot;,\n        &quot;Effect&quot;:&quot;Allow&quot;,\n      &quot;Principal&quot;: &quot;*&quot;,\n      &quot;Action&quot;:[&quot;s3:GetObject&quot;],\n      &quot;Resource&quot;:[&quot;arn:aws:s3:::sapd-test-bucket-private/*&quot;\n      ]\n    }\n  ]\n}\n'
   CORS:      none
   ACL:       *anon*: READ
   ACL:       sapd@vccloud.vn: FULL_CONTROL
   URL:       http://sapd-test-bucket-private.ss-hn-1.vccloud.vn/
</code></pre>
<!--kg-card-end: markdown--><p></p><p>Thực hiện truy cập vào file trong bucket.</p><p>Tada</p><figure class="kg-card kg-image-card"><img src="http://engineering.bizflycloud.vn/content/images/2020/07/Screenshot-from-2020-07-12-22-18-12.png" class="kg-image"></figure><p></p><p>References:</p><p>[1] - <a href="https://support.bizflycloud.vn/knowledge-base/dung-client-tool-ket-noi-voi-simple-storage/">https://support.bizflycloud.vn/knowledge-base/dung-client-tool-ket-noi-voi-simple-storage/</a></p>]]></content:encoded></item><item><title><![CDATA[Triển khai CI/CD cho ứng dụng với BizFly Container Registry và BizFly Cloud Server]]></title><description><![CDATA[<hr><!--kg-card-begin: markdown--><h2 id="1giithiu">1. Giới thiệu</h2>
<p>CI/CD không còn là khái niệm mới, việc sử dụng CI/CD sẽ tiết kiệm rất nhiều thời gian cũng như việc deploy lặp đi lặp mỗi lần commit code. Và hiện tại thì cũng có nhiều công cụ hỗ trợ việc triển khai CI/CD</p>]]></description><link>http://engineering.bizflycloud.vn/su-dung-bizfly-container-registry-va-set-up-gitlab-ci-auto-deploy-to-bizfly-cloud-server/</link><guid isPermaLink="false">5ec208d7ac64d4008021683b</guid><category><![CDATA[blog]]></category><category><![CDATA[bizflycloud]]></category><dc:creator><![CDATA[tuda@vccloud.vn]]></dc:creator><pubDate>Mon, 25 May 2020 10:09:36 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1461749280684-dccba630e2f6?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<hr><!--kg-card-begin: markdown--><h2 id="1giithiu">1. Giới thiệu</h2>
<img src="https://images.unsplash.com/photo-1461749280684-dccba630e2f6?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Triển khai CI/CD cho ứng dụng với BizFly Container Registry và BizFly Cloud Server"><p>CI/CD không còn là khái niệm mới, việc sử dụng CI/CD sẽ tiết kiệm rất nhiều thời gian cũng như việc deploy lặp đi lặp mỗi lần commit code. Và hiện tại thì cũng có nhiều công cụ hỗ trợ việc triển khai CI/CD như gitlab, jenskin, Cirle CI...<br>
Mình sử dụng Gitlab-Ci vì Gitlab là hệ thống self-hosted mã nguồn mở gần gũi với nhiều người, khả năng hỗ trợ Ci của gitlab cũng khá đa dạng àm dễ dàng sử dụng.</p>
<p>Bài này mình sẽ giới thiệu về việc sử dụng:<br>
- Hướng dẫn sử dụng Bizfly Container Registry.<br>
- set up CI tên gitlab để auto deploy lên server của Bizfly-cloud</p>
<p><img src="http://engineering.bizflycloud.vn/content/images/2020/05/Screenshot-from-2020-05-20-09-59-45.png" alt="Triển khai CI/CD cho ứng dụng với BizFly Container Registry và BizFly Cloud Server"></p>
<h2 id="2sdngbizflycontainerregistry">2. Sử dụng Bizfly Container Registry</h2>
<p>Giao diện quản lý Bizfly Container Registry tại: <a href="https://manage.bizflycloud.vn/container-registry">https://manage.bizflycloud.vn/container-registry</a><br>
Trên trang quản trị bạn chọn tạo mới rồi tiến hành đặt tên cho Repo.<br>
<img src="http://engineering.bizflycloud.vn/content/images/2020/05/Screenshot-from-2020-05-18-11-29-49.png" alt="Triển khai CI/CD cho ứng dụng với BizFly Container Registry và BizFly Cloud Server"><br>
Có 2 cách để login registry docker bizfly:<br>
- Sử dụng username và password tài khoản trên <a href="https://manage.bizflycloud.vn/:">https://manage.bizflycloud.vn/:</a> <code>docker login -u tuda@vccloud.vn -p ******** cr-hn-1.vccloud.vn</code><br>
- Sử dụng token:<br>
Thay vì sử dụng tài khoản và mật khẩu, bạn có thể sử dụng token để linh hoạt hoá thao tác xác thực và phân quyền. Bạn có thể đặt thời gian hết hạn cho token, gán quyền cụ thể cho token có thể thể truy cập tới một hoặc một số repository nhất định.<br>
Chọn thẻ Sử dụng token, tạo token như hình dưới :<br>
<img src="http://engineering.bizflycloud.vn/content/images/2020/05/Screenshot-from-2020-05-18-11-38-06.png" alt="Triển khai CI/CD cho ứng dụng với BizFly Container Registry và BizFly Cloud Server"><br>
Trên client thực hiện command sau: <code>docker login -u BIZFLY -p {token} cr-hn-1.vccloud.vn</code> (nếu sử dụng token thì username sẽ là BIZFLY)<br>
Push Images:<br>
- Mỗi repository sẽ có một URI tương ứng, bạn có thể sao chép URI này bằng cách nhấn vào biểu tượng như hình bên dưới.<br>
<img src="http://engineering.bizflycloud.vn/content/images/2020/05/container_registry_3.png" alt="Triển khai CI/CD cho ứng dụng với BizFly Container Registry và BizFly Cloud Server"><br>
Sau đó thực hiện tag image với URI và push image<br>
<img src="http://engineering.bizflycloud.vn/content/images/2020/05/Screenshot-from-2020-05-18-11-45-42.png" alt="Triển khai CI/CD cho ứng dụng với BizFly Container Registry và BizFly Cloud Server"><br>
Pull Images:<br>
- Tương tự với push images, pull images với URI của images.<br>
<img src="http://engineering.bizflycloud.vn/content/images/2020/05/Screenshot-from-2020-05-18-11-54-38.png" alt="Triển khai CI/CD cho ứng dụng với BizFly Container Registry và BizFly Cloud Server"></p>
<h2 id="3setupgitlabciautodeploytobizflycloudserver">3. Set-up gitlab-ci auto deploy to Bizfly Cloud Server</h2>
<p>- Trước khi thực hiện theo hướng dẫn bên dưới, bạn có cần cài đặt 1 gitlab-runner (mình làm theo <a href="https://docs.gitlab.com/runner/install/linux-manually.html">hướng dẫn này</a> ).<br>
- Register một gitlab runner theo Project:</p>
<pre><code>sudo gitlab-runner register -n \
  --url https://gitlab.com/tuda/tuda-test/ \
  --registration-token 8j6DuFYsjTUcqNJUv53q \
  --executor docker \
  --description &quot;test&quot; \
  --tag-list test-ci \
  --docker-image &quot;docker:19.03.6&quot; \
  --docker-volumes /var/run/docker.sock:/var/run/docker.sock \
</code></pre>
<p>( Ở đây mình đăng kí 1 runner dùng docker, các bạn có thể  đăng kí gitlab-runner với nhiều tùy chọn hơn <a href="https://docs.gitlab.com/runner/examples/gitlab.html">tại đây</a> )</p>
<p>- Xong phần set up tạo môi trường runner, giờ thì tiến hành viết gitlab-ci.yaml nào !!!!</p>
<ul>
<li>Ở trong ví dụ này, mình cấu trúc vòng ci gồm 3 stage: test, build , deploy.</li>
</ul>
<pre><code>stages:
  - test
  - build
  - deploy

variables:
  REGISTRY: cr-hn-1.vccloud.vn
  HUB_USERNAME: tuda@vccloud.vn
  PROJECT_NAME: tuda-test
  HUB_NAMESPACE: cr-hn-1.vccloud.vn/3683a522cf3c4afcbaf2eee2834ec080/tuda


before_script:
  - export CI_APPLICATION_TAG=$(echo $CI_COMMIT_SHA | cut -c 32-40)

test_tuda_test:
  stage: test
  script:
    - echo &quot;pass&quot;
  tags:
    - dockerm1

build_tuda_test:
  stage: build
  script:
    - docker build -t $HUB_NAMESPACE/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME:d$CI_APPLICATION_TAG .
    - echo ${HUB_USERNAME} ${HUB_PASSWORD} $REGISTRY
    - docker login -u ${HUB_USERNAME} -p ${HUB_PASSWORD} $REGISTRY
    - docker push $HUB_NAMESPACE/$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME:d$CI_APPLICATION_TAG
    - docker logout $REGISTRY

  tags:
    - dockerm1

deploy_tuda_test:
  stage: deploy
  image: ubuntu:18.04
  script:
    - apt update -y &amp;&amp; apt install sshpass -y
    - chmod -x ./deploy.sh
    - export LC_ALL=C.UTF-8
    - export LANG=C.UTF-8
    - sh ./deploy.sh $HUB_NAMESPACE $CI_PROJECT_NAME $CI_COMMIT_REF_NAME $CI_APPLICATION_TAG $SSH_PASSWORD $HUB_PASSWORD
  tags:
    - dockerm1
</code></pre>
<ul>
<li>Stage test có nhiệm vụ kiểm tra kết nối đến runner ( chỉ đơn giản là dòng scirpt echo &quot;pass&quot;</li>
<li>Stage build sẽ build image, tags, push mỗi khi có commit code</li>
<li>Stage deploy auto deploy (docker run) lên server cloud ( cụ thể mình dùng server tạo trên bizfly cloud)<br>
Đối với deploy lên một vm (server) thì có nhiều cách , ở đây mình dùng shell script để ssh và deploy trên server. ( Ngoài ra thì có thể dùng ansible hay 1 số tool ssh khác ).</li>
</ul>
<pre><code>sshpass -p $5 ssh -o 'StrictHostKeyChecking=no' root@103.107.182.249 &lt;&lt; ENDSSH
   export LC_ALL=C.UTF-8
   export LANG=C.UTF-8
   docker login -u tuda@vccloud.vn -p $6 cr-hn-1.vccloud.vn
   docker stop tuda-test
   docker rm tuda-test
   docker pull $1/$2-$3:d$4
   docker run --name=tuda-test $1/$2-$3:d$4
ENDSSH
</code></pre>
<p>Mình viết một đoạn bash script như trên sử dụng sshpass để deploy<br>
<img src="http://engineering.bizflycloud.vn/content/images/2020/05/Screenshot-from-2020-05-19-11-14-46.png" alt="Triển khai CI/CD cho ứng dụng với BizFly Container Registry và BizFly Cloud Server"></p>
<p>Shell Script chỉ là cách đơn giản dễ dàng để cho các bạn viết ci nhanh chóng, nếu trong quá trình làm có lỗi hoặc chưa hiểu, hoặc muốn giải các bài toán phức tạp hơn, deploy lên các môi trường khác như k8s, aws ... các bạn có thể để lại comment hoặc contact vs email của mình để mình có động lực ra các series tiếp theo nhé. Hẹn gặp lại !!!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Một số điểm mới trên phiên bản Openstack Ussuri]]></title><description><![CDATA[<p>Cách đây vài tiếng (9:50pm GMT+7 - 13/5/2020), Openstack Foundation đã release phiên bản thứ 21 mang tên Ussuri [1]. Tại phiên bản này theo mình đánh gía thì không có nhiều sự thay đổi lớn lắm. Ngoài việc python2 đã bị drop hoàn toàn và</p>]]></description><link>http://engineering.bizflycloud.vn/mot-so-diem-moi-tren-phien-ban-openstack-ussuri/</link><guid isPermaLink="false">5ebc1d36ac64d40080216797</guid><category><![CDATA[blog]]></category><category><![CDATA[openstack]]></category><dc:creator><![CDATA[Sa Pham]]></dc:creator><pubDate>Wed, 13 May 2020 17:03:59 GMT</pubDate><media:content url="http://engineering.bizflycloud.vn/content/images/2020/05/openstack-ussuri-580x358.png" medium="image"/><content:encoded><![CDATA[<img src="http://engineering.bizflycloud.vn/content/images/2020/05/openstack-ussuri-580x358.png" alt="Một số điểm mới trên phiên bản Openstack Ussuri"><p>Cách đây vài tiếng (9:50pm GMT+7 - 13/5/2020), Openstack Foundation đã release phiên bản thứ 21 mang tên Ussuri [1]. Tại phiên bản này theo mình đánh gía thì không có nhiều sự thay đổi lớn lắm. Ngoài việc python2 đã bị drop hoàn toàn và thay thế bởi python3 đối với toàn bộ core projects và một số project khác. Sau đây mình sẽ điểm qua một vài điểm mới trên phiên bản này với một số project chính</p><p></p><p><strong>Keystone</strong></p><p>Phiên bản này, đội ngũ phát triển của Keystone đã phải làm việc rất vất vả với số lượng security bug lớn. Ngay trước khi phiên bản Ussuri ra mắt thì đã có 1 loạt Security bug liên quan tới tính năng EC2/S3 và trust [2]. Hiện tại bug này đã được vá và đang được backport về các phiên bản cũ hơn (tới phiên bản Rocky).</p><p>Để tham khảo thêm các bug đã được fix trên phiên bản này các bạn truy cập [3] nhé.</p><p><strong>Nova</strong></p><p>Khác với Keystone, tại phiên bản này Nova có một số tính năng mới đáng chú ý như sau</p><p> - Khả năng pre-caching image với các aggregate host compute: phục vụ cho các nhu cầu edge computing hoặc một số Image được sử dụng nhiều. Sẽ được nova download trước tại các compute.</p><p>- Hỗ trợ cold migrate và resize server giữa các cell. Như các bạn đã biết việc nova hỗ trợ multi cells cách đây 2-3 phiên bản (từ Queens) nhưng tới phiên bản này việc cold migrate và resize server giữa các cell mới có thể thực hiện được.</p><p>- Cho phép audit các orphaned resource trên nova placement thông qua lệnh <code><strong>nova-manage placement audit</strong></code></p><p>- Cho phép tính năng rescue các VM có root disk là dạng volume-based</p><p>- Hỗ trợ thêm các role:<strong> system_reader_api, system_or_project_reader, project_member_api, system_admin_or_owner, system_admin_api, project_admin_api, system_admin_or_owner. </strong>Giúp việc phân quyền trên hệ thống Cloud Openstack tốt hơn</p><p>Ngoài các tính năng mới thì tại phiên bản này cũng đã fix một loạt các bug liên quan tới NUMA, migrate, resize same host,.. </p><p><strong>Neutron</strong></p><p>Các điểm  mới của Neutron:</p><p>- Address scopes và subnetpools có thể share giữa các Project(Tenant) thông qua RBAC policy</p><p>- Security group có thể thiết lập thành dạng stateful</p><p>- Networking-OVN driver hiện tại đã được merge vào code base của neutron. Giúp cho việc phát triển OVN được bám sát với neutron hơn. </p><p>Tại phiên bản này, Neutron cũng đã fix  flood  issue đối với OvS [4]. Cách đây không lâu thì team mình có test lại các patch. Nhưng có vẻ vấn đề chưa được xử lý 1 cách triệt để</p><p><strong>Cinder</strong></p><p>Ở phiên bản này không có tính năng nào mới đáng chú ý. Các Volume Driver vẫn được các provider hỗ trợ phát triển và cập nhật phiên bản.</p><p><strong>Glance</strong> </p><p>Các tính năng mới trên Glance tại phiên bản này đa số liên quan tới việc Glance hỗ trợ multiple stores của các image</p><p>- Cho phép import các image vào các store</p><p>- Cho phép copy các image trong các store</p><p>- Cho phép xóa image của 1 store</p><p></p><p>Trên đây là 1 vài dòng ghi nhanh của mình đối với phiên bản U này. Nếu các bạn có các cập nhật gì mới thì hãy comment bên dưới nhé. Xin cảm ơn.</p><p></p><p></p><p><strong>Reference</strong></p><p>[1] - <a href="http://lists.openstack.org/pipermail/openstack-announce/2020-May/002035.html">http://lists.openstack.org/pipermail/openstack-announce/2020-May/002035.html</a></p><p>[2] - <a href="https://bugs.launchpad.net/keystone/+bug/1872735">https://bugs.launchpad.net/keystone/+bug/1872735</a></p><p>[3] - <a href="https://docs.openstack.org/releasenotes/keystone/ussuri.html">https://docs.openstack.org/releasenotes/keystone/ussuri.html</a></p><p>[4] - <a href="https://bugs.launchpad.net/neutron/+bug/1732067">https://bugs.launchpad.net/neutron/+bug/1732067</a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Cài đặt etcd cluster với etcdadm]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Cụm từ <code>adm</code> không còn quá xa lạ đối với những ai đã từng cài đặt Kubernetes bằng kubeadm. Hiện nay có rất nhiều tool lấy cảm hứng từ <code>kubeadm</code> để đặt tên cho tool cài đặt 1 hệ thống như vậy (ví dụ có cephadm).</p>
<p>Trong bài này mình</p>]]></description><link>http://engineering.bizflycloud.vn/cai-dat-etcd-cluster-voi-etcdadm/</link><guid isPermaLink="false">5ead8d61ac64d4008021673d</guid><category><![CDATA[blog]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Sa Pham]]></dc:creator><pubDate>Sat, 02 May 2020 15:30:47 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Cụm từ <code>adm</code> không còn quá xa lạ đối với những ai đã từng cài đặt Kubernetes bằng kubeadm. Hiện nay có rất nhiều tool lấy cảm hứng từ <code>kubeadm</code> để đặt tên cho tool cài đặt 1 hệ thống như vậy (ví dụ có cephadm).</p>
<p>Trong bài này mình sẽ giới thiệu việc cài đặt etcd cluster sử dụng công cụ etcdadm. Đây là một công cụ khá mới, giúp cho việc cài đặt 1 cụm etcd 1 cách dễ dàng hơn.</p>
<p>Để cài đặt etcdad, ta cần thực hiện build từ source code, do release của etcdadm không có build sẵn binary.</p>
<p>Lưu ý: Yêu cầu phải cài đặt golang trên máy. Hiện mình đang dùng bản <code>go1.14.2</code></p>
<pre><code>root@sapd-ubuntu3:~/etcdadm# go version
go version go1.14.2 linux/amd64
</code></pre>
<p>Clone source code etcdadm từ github</p>
<pre><code>git clone https://github.com/kubernetes-sigs/etcdadm
</code></pre>
<p>Build binary</p>
<pre><code>make etcdadm
</code></pre>
<p>Sau khi build được etcdadm, ta thực hiện copy file binary này lên các node dự định cài đặt etcd.</p>
<p>Trong bày này, mình sẽ cài đặt trên 3 node có địa chỉ IP lần lượt như sau</p>
<ul>
<li>10.5.9.175</li>
<li>10.5.8.86</li>
<li>10.5.9.55</li>
</ul>
<p>Thực hiện khởi tạo cluster, gõ lệnh <code>./etcdadm init</code> trên 1 node. Output như sau:</p>
<pre><code>root@sapd-ubuntu3:~/etcdadm# ./etcdadm init
INFO[0000] [install] Artifact not found in cache. Trying to fetch from upstream: https://github.com/coreos/etcd/releases/download 
INFO[0000] [install] Downloading &amp; installing etcd https://github.com/coreos/etcd/releases/download from 3.3.8 to /var/cache/etcdadm/etcd/v3.3.8 
INFO[0000] [install] downloading etcd from https://github.com/coreos/etcd/releases/download/v3.3.8/etcd-v3.3.8-linux-amd64.tar.gz to /var/cache/etcdadm/etcd/v3.3.8/etcd-v3.3.8-linux-amd64.tar.gz 
######################################################################## 100.0% -#O#-  #   #                                                                 
INFO[0005] [install] extracting etcd archive /var/cache/etcdadm/etcd/v3.3.8/etcd-v3.3.8-linux-amd64.tar.gz to /tmp/etcd172607196 
INFO[0006] [install] verifying etcd 3.3.8 is installed in /opt/bin/ 
INFO[0006] [certificates] creating PKI assets           
INFO[0006] creating a self signed etcd CA certificate and key files 
[certificates] Generated ca certificate and key.
INFO[0006] creating a new server certificate and key files for etcd 
[certificates] Generated server certificate and key.
[certificates] server serving cert is signed for DNS names [sapd-ubuntu3] and IPs [10.5.9.55 127.0.0.1]
INFO[0006] creating a new certificate and key files for etcd peering 
[certificates] Generated peer certificate and key.
[certificates] peer serving cert is signed for DNS names [sapd-ubuntu3] and IPs [10.5.9.55]
INFO[0007] creating a new client certificate for the etcdctl 
[certificates] Generated etcdctl-etcd-client certificate and key.
INFO[0008] creating a new client certificate for the apiserver calling etcd 
[certificates] Generated apiserver-etcd-client certificate and key.
[certificates] valid certificates and keys now exist in &quot;/etc/etcd/pki&quot;
INFO[0011] [health] Checking local etcd endpoint health 
INFO[0011] [health] Local etcd endpoint is healthy      
INFO[0011] To add another member to the cluster, copy the CA cert/key to its certificate dir and run: 
INFO[0011] 	etcdadm join https://10.5.9.55:2379         
</code></pre>
<p>Tới bước này etcdadm đã thực hiện việc generate PKI Certificate trên node <code>10.5.9.55</code> tại thực mục <code>/etc/etcd/pki/</code></p>
<pre><code>root@sapd-ubuntu3:~/etcdadm# ls -lah /etc/etcd/pki/
total 48K
drwxr-xr-x 2 root root 4.0K May  2 22:09 .
drwxr-xr-x 3 root root 4.0K May  2 22:09 ..
-rw-r--r-- 1 root root 1.1K May  2 22:09 apiserver-etcd-client.crt
-rw------- 1 root root 1.7K May  2 22:09 apiserver-etcd-client.key
-rw-r--r-- 1 root root 1009 May  2 22:09 ca.crt
-rw------- 1 root root 1.7K May  2 22:09 ca.key
-rw-r--r-- 1 root root 1.1K May  2 22:09 etcdctl-etcd-client.crt
-rw------- 1 root root 1.7K May  2 22:09 etcdctl-etcd-client.key
-rw-r--r-- 1 root root 1.1K May  2 22:09 peer.crt
-rw------- 1 root root 1.7K May  2 22:09 peer.key
-rw-r--r-- 1 root root 1.1K May  2 22:09 server.crt
-rw------- 1 root root 1.7K May  2 22:09 server.key
</code></pre>
<p>Để các node khác có thể join vào cụm etcd này, ta cần thực hiện copy toàn certificate và key của CA tại thư mục này sang các node member còn lại:</p>
<pre><code>rsync -avR /etc/etcd/pki/ca.* root@10.5.9.175:/
rsync -avR /etc/etcd/pki/ca.* root@10.5.8.86:/
</code></pre>
<p>Thực hiện join 2 node còn lại</p>
<pre><code>./etcdadm join https://10.5.9.55:2379  
</code></pre>
<p>Kiểm tra danh sách member bằng <code>etcdctl</code></p>
<pre><code>root@sapd-ubuntu3:~/etcdadm/etcd-v3.3.8-linux-amd64# ./etcdctl --cert-file /etc/etcd/pki/etcdctl-etcd-client.crt --key-file /etc/etcd/pki/etcdctl-etcd-client.key --ca-file /etc/etcd/pki/ca.crt --endpoints https://10.5.9.55:2379 member  list
223f95c9dff0b55: name=sapd-ubuntu-2 peerURLs=https://10.5.8.86:2380 clientURLs=https://10.5.8.86:2379 isLeader=false
983953b13a9e0a4: name=sapd-ubuntu-1 peerURLs=https://10.5.9.175:2380 clientURLs=https://10.5.9.175:2379 isLeader=false
b627deeadb65a889: name=sapd-ubuntu3 peerURLs=https://10.5.9.55:2380 clientURLs=https://10.5.9.55:2379 isLeader=true
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Monitor disk size of VM]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="1giithiu">1. Giới thiệu</h2>
<p>- Có rất nhiều công cụ dùng để thu thập các metrics của HOST và VM như Collectd, Stats, Telegraf, Promethus, Diamond,...<br>
- Mình sử dụng công cụ Diamond để thu thập các metrics của HOST và các VM chạy trên HOST đó. Diamond được viết bằng</p>]]></description><link>http://engineering.bizflycloud.vn/monitor-disk-size-of-vm/</link><guid isPermaLink="false">5ea64f92ac64d400802166c8</guid><category><![CDATA[blog]]></category><dc:creator><![CDATA[Son Do Xuan]]></dc:creator><pubDate>Mon, 27 Apr 2020 03:39:46 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="1giithiu">1. Giới thiệu</h2>
<p>- Có rất nhiều công cụ dùng để thu thập các metrics của HOST và VM như Collectd, Stats, Telegraf, Promethus, Diamond,...<br>
- Mình sử dụng công cụ Diamond để thu thập các metrics của HOST và các VM chạy trên HOST đó. Diamond được viết bằng Python, vì vậy ta có thể dễ dàng sửa đổi code, cũng như code thêm 1 số plugin #. Tham khảo source code diamond:<br>
<a href="https://github.com/python-diamond/Diamond">https://github.com/python-diamond/Diamond</a></p>
<p>- Bài này mình sẽ giới thiệu về việc sử dụng:</p>
<ul>
<li>Diammond để thu thập <code>disk size và disk partitions size</code>.</li>
<li>InfluxDB để lưu trữ dữ liệu các metrics.</li>
<li>Grafana để generate dữ liệu thành các biểu đồ tiện theo dõi.</li>
</ul>
<h2 id="2diamond">2. Diamond</h2>
<p>- Diamond có plugin <code>LibvirtKVMCollector</code> để thu thập các metrics của VM như CPU, Memory,... Tuy vậy, nếu bạn muốn thu thập <code>disk size và disk partitions size</code> của VM thì Diamond chưa hỗ trợ.<br>
Vì vậy, ta cần code thêm plugin để có thu thập <code>disk size và disk partitions size</code>.<br>
- Thư viện <code>libivrt</code> không hỗ trợ lấy <code>disk size và disk partitions size</code> của VM, nên ta phải dùng thư viện bên thứ 3 là <code>libguestFS</code> (<a href="http://libguestfs.org/">http://libguestfs.org/</a> ).<br>
Kết hợp 2 thư viện <code>libivirt</code> và <code>libguestfs</code>, ta có thể thu thập metrics <code>disk size và disk partitions size</code> của tất cả các VM đang chạy trên HOST tương đối dễ dàng.<br>
- Ví dụ code lấy <code>disk size và disk partitions size</code>:</p>
<pre><code>#!/usr/bin/python3

import libvirt
import guestfs

# Get disks and disk partitions size of of domain
def get_disks_and_parts_size (conn, dom_name):
    # Connect to domain &quot;dom_name&quot;
    dom1 = conn.lookupByName(dom_name)
    if dom1 == None:
        print('Failed to find the domain '+dom_name)
        exit(1)

    # All new Python code should pass python_return_dict=True
    # to the constructor.  It indicates that your program wants
    # to receive Python dicts for methods in the API that return
    # hashtables.
    g = guestfs.GuestFS(python_return_dict=True)

    # Attach the disk image read-only to libguestfs.
    g.add_libvirt_dom(dom=dom1, readonly=True)

    # Run the libguestfs back-end.
    g.launch()

    # Get disks total size of VM
    disks = g.list_devices()    # ['/dev/sda', '/dev/sdb']
    disks_total_size = {}   # {'/dev/sda': 41126400, '/dev/sdb': 21474836480}
                            # unit is byte

    for disk in disks:
        size_of_disk_total = g.blockdev_getsize64(disk)
        disks_total_size[disk] = size_of_disk_total

    # Get disk partitions size of VM
    partitions_size = []    # [ ['/dev/sda1', '2058100', '988608', '1053108', '49%', '/sysroot'] ; 
                            #   ['/dev/sda15', '106858', '3668', '103190', '4%', '/sysroot'] ]
                            # unit is KiB
    partitions = g.list_partitions()

    for partition in partitions:
        try:
            g.mount_ro(partition, &quot;/&quot;)
        except RuntimeError:
            continue
        df_list = g.df()
        df_list_line = df_list.splitlines()
        partition_size = df_list_line[5].split()
        partitions_size.append(partition_size)
</code></pre>
<h2 id="3influxdbvgrafana">3. InfluxDB và Grafana</h2>
<p>- Sau khi Diamond thu thập được <code>disk size và disk partitions size</code>, ta sẽ gửi các metrics đó đến InflubDB. Cuối cùng ta dùng Grafana để generate các dữ liệu đó và được biểu đồ, hình dưới minh họa các biểu đồ về  <code>disk size và disk partitions size</code>:<br>
<img src="http://engineering.bizflycloud.vn/content/images/2020/04/screenshot.png" alt="screenshot"></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Secure các application bằng oAuth2 không cần sửa code]]></title><description><![CDATA[<p></p><!--kg-card-begin: markdown--><p>Vừa rồi mình có nhận được yêu cầu triển khai một ứng dụng opensource (không tiện nói tên). Ứng dụng này không không authentication, ai cũng có thể truy cập vào được, do vậy việc ứng dụng triển khai thì có một số cách</p>
<ul>
<li>
<p>Custom thêm hệ thống xác thực</p></li></ul>]]></description><link>http://engineering.bizflycloud.vn/secure-cac-application/</link><guid isPermaLink="false">5e8c3a01b760f400f2aa7a7e</guid><category><![CDATA[blog]]></category><dc:creator><![CDATA[Sa Pham]]></dc:creator><pubDate>Tue, 07 Apr 2020 08:51:16 GMT</pubDate><media:content url="http://engineering.bizflycloud.vn/content/images/2020/04/eeb5b100-faff-11e9-9b0b-a97d43094103.jpg" medium="image"/><content:encoded><![CDATA[<img src="http://engineering.bizflycloud.vn/content/images/2020/04/eeb5b100-faff-11e9-9b0b-a97d43094103.jpg" alt="Secure các application bằng oAuth2 không cần sửa code"><p></p><!--kg-card-begin: markdown--><p>Vừa rồi mình có nhận được yêu cầu triển khai một ứng dụng opensource (không tiện nói tên). Ứng dụng này không không authentication, ai cũng có thể truy cập vào được, do vậy việc ứng dụng triển khai thì có một số cách</p>
<ul>
<li>
<p>Custom thêm hệ thống xác thực</p>
</li>
<li>
<p>Secure bằng VPN</p>
</li>
</ul>
<p>Nhưng những cách trên thì sẽ có vài nhược điểm như triển khai lâu, phức tạp và yêu cầu người sử dụng phải có tài khoản VPN của hệ thống.</p>
<p>Sau một hồi suy nghĩ thì có 1 anh đồng nghiệp đưa giải pháp đó là Oauth2-Proxy [1]. Khi sử dụng proxy này thì ta có thể tích hợp được với các IdP có hỗ trợ OAuth2, ví dụ:</p>
<ul>
<li>Google</li>
<li>Github</li>
<li>Azure</li>
<li>Facebook</li>
<li>...</li>
<li>NextCloud</li>
</ul>
<p><code>oAuth2-proxy</code> là một proxy nên hoạt động như Nginx hay Haproxy, nhưng một số ứng dụng đặc thù không thể chỉ config upstream như [2].</p>
<pre><code>## the http url(s) of the upstream endpoint. If multiple, routing is based on path
# upstreams = [
#     &quot;http://127.0.0.1:8080/&quot;
# ]
</code></pre>
<p>Do vậy để có thể hoạt động ổn hơn, ta sẽ kết hợp Nginx với module <code>auth_request</code> vào làm proxy đứng trước <code>oAuth2-Proxy</code>. Mô hình như sau</p>
<pre><code>             Client

                |
                |
                |
                |
                |
         +------+-------+
         |              |
         |     Nginx    |
         |              |
         |              |
         +--+------+----+
            |      |
            |      |
            |      +---------+------------------+
            |                |                  |
+-----------+---+         +--+--------+    +----+-----+
|               |         |           |    |          |
|               |         |           |    |          |
|  oAuth2-Proxy |         | App-1     |    | App-2    |
|               |         |           |    |          |
|               |         |           |    |          |
+---------------+         +-----------+    +----------+
</code></pre>
<ul>
<li>
<p>Với <code>auth_request</code> module, thì các request tới nginx đều được kiểm tra trên 1 endpoint khác (ở đây là oAuth2-Proxy)</p>
</li>
<li>
<p>Sau khi oAuth2-Proxy kiểm tra request thì sẽ cho phép truy cập vào <code>App-1</code> hoặc <code>App-2</code> dựa trên location request</p>
</li>
</ul>
<p>Ta có file cấu hình Nginx như sau</p>
<pre><code>server {
    listen       80;
    server_name  localhost;

  location /oauth2/ {
    proxy_pass       http://oauth-proxy:4180;
    proxy_set_header Host                    $host;
    proxy_set_header X-Real-IP               $remote_addr;
    proxy_set_header X-Scheme                $scheme;
    proxy_set_header X-Auth-Request-Redirect $request_uri;
  }

  location / {
    auth_request /oauth2/auth;
    error_page 401 = /oauth2/start;

    auth_request_set $auth_cookie $upstream_http_set_cookie;
    add_header Set-Cookie $auth_cookie;

    location /app1 {
        proxy_pass http://app1;
    }

    location /app2 {
        proxy_pass http://app2;
    }
  }

}
</code></pre>
<h3 id="reference">Reference</h3>
<p>[1] - <a href="https://github.com/oauth2-proxy/oauth2-proxy">https://github.com/oauth2-proxy/oauth2-proxy</a><br>
[2] - <a href="https://github.com/oauth2-proxy/oauth2-proxy/blob/master/contrib/oauth2-proxy.cfg.example#L20">https://github.com/oauth2-proxy/oauth2-proxy/blob/master/contrib/oauth2-proxy.cfg.example#L20</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Kiểm tra và đánh giá storage]]></title><description><![CDATA[<h3 id="c-c-ti-u-ch-ki-m-tra-v-nh-g-a">Các tiêu chí kiểm tra và đánh gía</h3><ul><li>Bandwidth</li><li>IOPS</li><li>Latency</li></ul><p><strong>Tool: Flexible I/O Tester(fio)</strong></p><p>Cài đặt: <code>sudo apt-get install fio</code> trên Ubuntu hoặc sudo yum install fio -y trên Centos/RHEL</p><p><strong>Kiểm tra tốc độ ghi:</strong> <code>sudo fio --name=randwrite --ioengine=libaio --iodepth=1 --rw=randwrite --bs=</code></p>]]></description><link>http://engineering.bizflycloud.vn/kiem-tra-va-danh-gia-storage/</link><guid isPermaLink="false">5e8ab7a3b760f400f2aa7a42</guid><category><![CDATA[blog]]></category><dc:creator><![CDATA[Sa Pham]]></dc:creator><pubDate>Mon, 06 Apr 2020 05:05:38 GMT</pubDate><content:encoded><![CDATA[<h3 id="c-c-ti-u-ch-ki-m-tra-v-nh-g-a">Các tiêu chí kiểm tra và đánh gía</h3><ul><li>Bandwidth</li><li>IOPS</li><li>Latency</li></ul><p><strong>Tool: Flexible I/O Tester(fio)</strong></p><p>Cài đặt: <code>sudo apt-get install fio</code> trên Ubuntu hoặc sudo yum install fio -y trên Centos/RHEL</p><p><strong>Kiểm tra tốc độ ghi:</strong> <code>sudo fio --name=randwrite --ioengine=libaio --iodepth=1 --rw=randwrite --bs=4k --direct=0 --size=512M --numjobs=2 --runtime=240 --group_reporting</code></p><p>Câu lệnh này sẽ kiểm tra tốc độ ghi, tên file : <code>randwrite</code>, kích cỡ: <code>512MB</code>, chạy 4 jobs và 2 process  (tổng cộng 4GB)</p><figure class="kg-card kg-image-card"><img src="https://raw.githubusercontent.com/bizflycloud/internship-0719/master/quanlm1999/pic/fio_W_test.png" class="kg-image" alt="write"></figure><p>Ta thấy bandwidth và IOPS: <code>write: IOPS=6315, BW=24.7MiB/s (25.9MB/s)(1024MiB/41507msec)</code></p><p><strong>Kiểm tra tốc độ đọc</strong>: <code>sudo fio --name=randread --ioengine=libaio --iodepth=16 --rw=randread --bs=4k --direct=0 --size=512M --numjobs=4 --runtime=240 --group_reporting</code> Đọc file ngẫu nhiên tổng cộng 2GB</p><figure class="kg-card kg-image-card"><img src="https://raw.githubusercontent.com/bizflycloud/internship-0719/master/quanlm1999/pic/fio_R_test.png" class="kg-image" alt="read"></figure><p>Ta thấy bandwidth và IOPS: <code>read: IOPS=4173, BW=16.3MiB/s (17.1MB/s)(2048MiB/125615msec)</code></p><p><strong>Kiểm tra tốc độ đọc ghi:</strong> <code>sudo fio --randrepeat=1 --ioengine=libaio --direct=1 --gtod_reduce=1 --name=test --filename=random_read_write.fio --bs=4k --iodepth=64 --size=4G --readwrite=randrw --rwmixread=75</code> tổng cộng 4 GB</p><figure class="kg-card kg-image-card"><img src="https://raw.githubusercontent.com/bizflycloud/internship-0719/master/quanlm1999/pic/fio_RW.png" class="kg-image" alt="readwrite"></figure><p>Ta thấy bandwidth và IOPS: <code>read: IOPS=2275, BW=9104KiB/s (9322kB/s)(3070MiB/345321msec)</code> và <code> write: IOPS=760, BW=3042KiB/s (3115kB/s)(1026MiB/345321msec)</code></p><h3 id="ki-m-tra-t-c-ghi-c-tu-n-t-">Kiểm tra tốc độ ghi đọc tuần tự</h3><p>Command: dd<br>Đọc: <code>dd if=/dev/zero of=/tmp/laptop.bin bs=1G count=1 oflag=direct</code> Ghi 1 file 1GB<br>Ghi: <code>dd if=/dev/zero of=/tmp/test1.img bs=1G count=1 oflag=dsync</code> Đọc 1 file 1GB<br>Kiểm tra latency(thời gian thao tác đến lúc hoàn thành): <code>dd if=/dev/zero of=/tmp/test2.img bs=512 count=1000 oflag=dsync</code> ghi 512byte 1000 lần</p><p>ví dụ:<br></p><figure class="kg-card kg-image-card"><img src="https://raw.githubusercontent.com/bizflycloud/internship-0719/master/quanlm1999/pic/dd.png" class="kg-image" alt="dd"></figure><h3 id="ki-m-tra-tr-">Kiểm tra độ trễ</h3><p>Tool: ioping</p><p>Cài đặt: <code>sudo apt-get install ioping</code><br>Câu lệnh: <code>ioping -c "n"</code> Trong đó n là số request</p><p>Ví dụ: n = 10<br></p><figure class="kg-card kg-image-card"><img src="https://raw.githubusercontent.com/bizflycloud/internship-0719/master/quanlm1999/pic/ioping.png" class="kg-image" alt="ioping"></figure><p>Trong đó 529,5 us = 0,5295 ms</p><h3 id="gi-m-s-t-c-c-disk">Giám sát các Disk</h3><p>Tool: iostat, htop</p><p>Cài đặt: <code>sudo apt-get install sysstat</code></p><ul><li>Theo dõi report từ boot: <code>iostat</code></li><li>Theo dõi liên tục mỗi n giây: <code>iostat "n"</code></li><li>Theo dõi n lần, mỗi lần cách m giây: <code>iostat m n</code></li></ul><p>Ví dụ:<br></p><figure class="kg-card kg-image-card"><img src="https://raw.githubusercontent.com/bizflycloud/internship-0719/master/quanlm1999/pic/iostat.png" class="kg-image" alt="iostat"></figure><p>Trong đó các thông số: avg-cpu: trung bình các cpu</p><p>3 giá trị về % CPU</p><ul><li>%user: phần trăm CPU được sử dụng khi chạy các ứng dụng ở user level (tất cả những gì không thuộc về kernel)</li><li>%system: phần trăm CPU được sử dụng khi chạy ở system level (kernel)</li><li>%nice: tương tự %user nhưng với nice priority.</li></ul><p>3 giá trị về % thời gian</p><ul><li>%iowait: phần trăm thời gian mà CPU(s) rảnh  khi hệ thống thực hiện disk I/O request.</li><li>%idle: phần trăm thời gian mà CPU(s) rảnh và hệ thống không thực hiện disk I/O request.</li><li>%steal: phần trăm thời gian dành cho chờ đợi của CPU hoặc CPU ảo trong khi bộ ảo hóa đang phục vụ một bộ xử lý ảo khác.</li></ul><p>6 giá trị về device:</p><ul><li>Device: tên device, ở đây là "sda". Một device có 1 hay nhiều partition. (dùng iostat -pd sda để hiển thị thông số cho từng partition trong sda)</li><li>tps: transfer per second. Mỗi  transfer là một I/O request đến device. Nhiều logical request có thể được hợp lại thành 1 I/O request đến device =&gt;  một transfer không có kích thước cố định.</li><li>kB_read/s: số kilobytes đọc từ device</li><li>kB_read: tổng số kilobytes đọc từ device  = kB_read/s * interval (s)</li><li>k B_wrtn/s: số kilobytes ghi vào device</li><li>kB_wrtn: tổng số kilobytes ghi  từ device  = kB_read/s * interval (s)</li></ul><h3></h3><h1 id="-nh-gi-">Đánh giá</h1><p>- IOPS: Càng cao càng tốt</p><p>-Lantency: Càng thấp càng tốt</p><p>- Bandwidth: Càng cao càng tốt</p>]]></content:encoded></item><item><title><![CDATA[Cài đặt Ceph Octopus với Cephadm]]></title><description><![CDATA[<p>Ceph có nhiều công cụ triển khai được ra đời với mục đích làm cho Ceph dễ cài đặt và quản lý. Trong đó, Ceph-deploy là một tool đơn giản và dễ hiểu (ít nhất đổi với người có kiến thức với Ceph). Ceph-deploy đã không còn được mantained, thậm</p>]]></description><link>http://engineering.bizflycloud.vn/cai-dat-ceph-oc/</link><guid isPermaLink="false">5e8ab70db760f400f2aa7a35</guid><category><![CDATA[blog]]></category><dc:creator><![CDATA[Vu Vinh]]></dc:creator><pubDate>Mon, 06 Apr 2020 05:01:56 GMT</pubDate><media:content url="http://engineering.bizflycloud.vn/content/images/2020/04/Ceph_Logo_Standard_RGB_120411_fa.png" medium="image"/><content:encoded><![CDATA[<img src="http://engineering.bizflycloud.vn/content/images/2020/04/Ceph_Logo_Standard_RGB_120411_fa.png" alt="Cài đặt Ceph Octopus với Cephadm"><p>Ceph có nhiều công cụ triển khai được ra đời với mục đích làm cho Ceph dễ cài đặt và quản lý. Trong đó, Ceph-deploy là một tool đơn giản và dễ hiểu (ít nhất đổi với người có kiến thức với Ceph). Ceph-deploy đã không còn được mantained, thậm chí không hoạt động trên một số distro mới như RHEL/CentOS 8.</p><h3 id="cephadm">Cephadm</h3><p>Mục tiêu là Cephadm là cung cấp đầy đủ tính năng, mạnh mẽ, cung cấp việc cài đặt và quản lý cho bất cứ ai không chạy Ceph trong Kubernetes. Mục tiêu của Cephadm bao gồm:</p><ul><li><strong>Deploy all components in containers</strong>: Sử dụng containers để làm đơn giản hóa việc phụ thuộc package trên các bản phân phối khác nhau.</li><li><strong>Tight intergration with the orchestrator API</strong>:</li><li><strong>No dependency on management tools</strong>: Các tool như Salt hay Ansible tuyệt vời khi triển khai ở quy mô lớn, nhưng nó làm Ceph phụ thuộc vào tool, có nghĩa là người dùng sẽ phải tìm hiểu thêm một phần mềm. Quan trọng hơn là triển khai sẽ phức tạp hơn, khó debug hơn</li><li><strong>Minimal OS dependencies</strong>: Cephadm requires Python3, LVM và container runtime( Podman hoặc Docker). Tất cả Linux distro hiện nay đều có thể làm được</li><li><strong>Isolate clusters from each other</strong>:</li><li><strong>Automated upgrades</strong>: Ceph có thể upgrade một cách an toàn và tự động</li><li><strong>Easy migration from "legacy" deployment tools</strong>: Cephadmn cho phép convert  Ceph cluster đang tồn tại được deploy bởi các tool đang tồn tại như ceph-ansible, ceph-deploy, DeepSea hay các tool tương tự</li></ul><p>Mục tiêu là để tập chung sự chú ý của Ceph developer và người dùng chỉ trên 2 nền tảng cho việc triển khai và quản lý Ceph, cephadm dùng cho "bare metal" và Rook để chạy Ceph trong Kubernetes</p><h3 id="deploy-ceph-cluster-s-d-ng-cephadm">Deploy Ceph Cluster sử dụng Cephadm</h3><h4 id="requirements">Requirements</h4><ul><li>Systemd</li><li>Podman hoặc Docker để chạy containers</li><li>Chrony hoặc NTP để đồng bộ thời gian</li><li>LVM2</li></ul><h4 id="install-cephadm">Install Cephadm</h4><p>Câu lệnh <strong>cephadmn</strong> có thể bootstrap một cluster mới, khởi động contrainerized shell để làm việc với Ceph CLI</p><p>Sử dụng <strong>curl</strong> để lấy phiên bản script mới nhất để cài đặt cephadm:</p><pre><code>curl --silent --remote-name --location https://github.com/ceph/ceph/raw/octopus/src/cephadm/cephadm
chmod +x cephadm
</code></pre><p>Cài đặt packages cho phiên bản <strong>Octopus</strong>:</p><pre><code>./cephadm add-repo --release octopus
./cephadm install
</code></pre><h4 id="bootstrap-cluster-m-i">Bootstrap cluster mới</h4><p>Để bootstrap cluster ta dùng câu lệnh:</p><pre><code>mkdir -p /etc/ceph
cephadm bootstrap --mon-ip *&lt;mon-ip&gt;*
</code></pre><p>Output khi thành công sẽ giống như:</p><pre><code>INFO:cephadm:Ceph Dashboard is now available at:

             URL: https://cephadm:8443/
            User: admin
        Password: lb777day77

INFO:cephadm:You can access the Ceph CLI with:

        sudo /usr/sbin/cephadm shell --fsid f5429e0c-7737-11ea-b0fe-fa163e9a2068 -c /etc/ceph/ceph.conf -k /etc/ceph/ceph.client.admin.keyring

INFO:cephadm:Please consider enabling telemetry to help improve Ceph:

        ceph telemetry on

For more information see:

        https://docs.ceph.com/docs/master/mgr/telemetry/

INFO:cephadm:Bootstrap complete.
</code></pre><p>Lệnh này sẽ:</p><ul><li>Tạo một monitor và manager daemon cho cluster mới trên localhost</li><li>Generate một SSH key mới cho Ceph cluster và add key vào <code>/root/.ssh/authorized_keys</code></li><li>Viết một minimal configuration để giao tiếp với cluster mới vào <code>/etc/ceph/ceph.conf</code></li><li>Viết một bản copy của public key vào <code>/etc/ceph/ceph.pub</code></li></ul><p>Default bootstrap sẽ làm một số việc cho đa số người dùng. Ta có thể xem một số options để bootstrap cluster bằng câu lệnh <code>cephadm bootstrap -h</code></p><h4 id="enable-ceph-cli">Enable Ceph CLI</h4><p><strong>Cephadm</strong> không yêu cầu Ceph package cài đặt trên host. Để truy cập vào câu lệnh <strong>ceph</strong>:</p><ul><li>Câu lệnh <code>cephadm shell</code> sẽ chạy 1 bash shell trong container được cài đặt tất cả Ceph packages</li></ul><pre><code>cephadm shell
</code></pre><p>Ta có thể dùng alias để truy cập nhanh vào Ceph CLI ví dụ:</p><pre><code>alias ceph='cephadm shell'
</code></pre><h4 id="add-hosts-to-the-cluster">Add hosts to the cluster</h4><p>Để thêm host mới cho cluster, thực hiện 2 bước sau:</p><ol><li>Install SSH public key của cluster trong host mới:</li></ol><p><code>ssh-copy-id -f -i ceph.pub root@*&lt;new-host&gt;*</code></p><ol><li>Truy cập vào cephadm shell và nói cho Ceph node mới là một phần của cluster:</li></ol><p><code>ceph orch host add *newhost*</code></p><h4 id="deploy-additional-montitor">Deploy additional montitor</h4><p>Khi Ceph biết địa chỉ IP subnet monitor có thể sử dụng nó có thể tự động deploy và scale monitor. Mặc định, Ceph giả định các monitor khác sử dụng cùng subnet với subnet IP của monitor đầu tiên</p><p>Nếu Ceph monitor (hoặc toàn bộ cluster) chạy trên một subnet duy nhất thì mặc định <strong>cephadm</strong> sẽ tự động thêm vào 5 monitor khi add host mới vào cluster.</p><ul><li>Ta có thể cấu hình IP subnet được sử dụng bởi monitors bằng CIDR format:</li></ul><pre><code>ceph config set mon public_network 10.5.0.0/16*
</code></pre><ul><li>Nếu ta muốn điều chỉnh số mon tự thêm vào mặc định xuống 3 mon:</li></ul><pre><code>ceph orch apply mon 3
</code></pre><ul><li>Ta có thể control host monitor bằng cách sử dụng <code>host labels</code>. Để set <code>mon</code> label dành cho host</li></ul><pre><code>ceph orch host label add *&lt;hostname&gt;* mon
</code></pre><ul><li>Để view các hosts hiện tại và labels:</li></ul><pre><code>[ceph: root@node1 /]# ceph orch host ls
HOST   ADDR   LABELS   STATUS
node1  node1  mon
node2  node2  osd
node3  node3  osd mon
</code></pre><ul><li>Triển khai monitor dựa trên các label:</li></ul><pre><code>ceph orch apply mon label:mon
</code></pre><ul><li>Disable tự động triển khai monitor:</li></ul><pre><code>ceph orch apply mon --unmanaged
</code></pre><ul><li>Add thêm từng mon:</li></ul><pre><code>ceph orch daemon add mon *&lt;host1:ip-or-network1&gt; [&lt;host1:ip-or-network-2&gt;...]*
</code></pre><p>Ví dụ deploy thêm một monitor trên <code>node2</code> sử dụng địa chỉ IP <code>10.5.10.172</code></p><pre><code>ceph orch apply mon --unmanaged
ceph orch daemon add mon node2:10.5.10.172
</code></pre><h4 id="deploy-osds">Deploy OSDs</h4><p>Một danh mục các devices trên các hosts trong cluster có thể được hiển thị với:</p><pre><code>ceph orch device ls
</code></pre><p>Một storage device được coi là <code>available</code> nếu đáp ứng các điều kiện sau:</p><ul><li>Device không có partitions</li><li>Device không có LVM state</li><li>Device không được mounted</li><li>Device không chứa filesystem</li><li>Device không chứa Ceph BlueStore OSD</li><li>Device phải có kích thước lớn hơn 5GB</li></ul><p>Ceph sẽ từ chối cung cấp OSD trên các device not available</p><p>Một số cách để tạo OSDs:</p><ul><li>Tạo OSD trên các device available và không được sử dụng:</li></ul><pre><code>ceph orch apply osd --all-available-devices
</code></pre><ul><li>Tạo OSD bằng cách chỉ định device cụ thể trên một host cụ thể, ví dụ device <code>/dev/vdb</code> trên host <code>node2</code></li></ul><pre><code>ceph orch daemon add osd node2:/dev/vdb
</code></pre>]]></content:encoded></item></channel></rss>