- vừa được xem lúc

Dockerize project demo microservices của Google

0 0 5

Người đăng: Mai Trung Đức

Theo Viblo Asia

Hello các bạn lại là mình đây 👋👋

Lâu rồi chưa được viết bài thêm nay lại thấy ngứa tay rồi, không biết dạo này công việc của các bạn như thế nào rồi nhỉ? 😚

Hôm nay ta lại tiếp tục với series Docker với một bài deploy full project e-commerce theo kiến trúc microservice, lấy từ demo của Google nhé. 🚀🚀

Câu chuyện là...

Câu chuyện là mình có được một người em chỉ cho xem repo này: https://github.com/GoogleCloudPlatform/microservices-demo

Ở đó ta có demo về một project e-commerce tới từ Google, với đầy đủ các service, mỗi service lại code bằng ngôn ngữ khác nhau, chạy độc lập, mình có xem tất cả những gì có trong repo đó và thấy là họ làm rất chỉn chu cho mục đích demo để ta có thể hiểu được một kiến trúc microservices khi deploy thật trông nó sẽ như thế nào.

Nhận thấy đây là một mảnh ghép còn thiếu cho series của mình, vậy là lại có ý tưởng viết bài mới liền 😝

Những thứ ta sẽ làm

Ở bài ngày hôm nay ta sẽ clone project của Google về: https://github.com/GoogleCloudPlatform/microservices-demo

Sau đó sẽ build từng service và cuối cùng là chạy project lên xem tổng thể như thế nào nhé. Thực tế bài này sẽ không dài, vì project của họ đã cho ta tất cả các file Dockerfile sẵn luôn rồi 😂

Mục đích của mình ở bài này như sau:

  • showcase dockerize/deploy microservices với Docker như thật sẽ thế nào
  • Flow build và run các services để giảm thiểu lỗi
  • xử lý các vấn đề liên quan trong quá trình build

Tổng quan

Ở đây ta có sơ đồ kiến trúc như sau: (cái này người ta đã cho sẵn ở repo của họ luôn)

Ở trên ta có tất thảy 11 services chính, cộng cả redis thì là 12, service nào call vào đâu đều được thể hiện rõ trên diagram

Thường khi ta làm thực tế, thì việc vẽ ra được sơ đồ như này rất quan trọng, lí do là để ta có thể hiểu được sự phục thuộc của các service vào với nhau, phân chia network/VPC như nào cho phù hợp, hiểu được request flow thì khi gặp lỗi sẽ dễ hơn cho ta debug

Không vẽ ra được thì ta cũng phải đảm bảo là viết doc cho nó ở đâu đó nha 😎

Dựa vào diagram ta có, lát nữa ta sẽ dockerize làm 2 lần:

  • lần 1: các service không cần gọi vào service khác. Ví dụ: ad, productcatalog, cart (cái này gọi vào redis nhưng về mặt business ta cũng coi như nó không gọi vào serviec khác),...
  • lần 2: các service phụ thuộc vào service khác, ví dụ: frontend, checkout, loadgenerator,...

Bên dưới ta có chi tiết từng service như sau:

Service Ngôn ngữ Mô tả
frontend Go Là 1 HTTP server. Không yêu cầu đăng ký/đăng nhập và tự động tạo session ID cho tất cả người dùng.
cartservice C# Lưu trữ các sản phẩm trong giỏ hàng của người dùng trên Redis và truy xuất sau này.
productcatalogservice Go Cung cấp danh sách sản phẩm từ file JSON, cho phép tìm kiếm và lấy thông tin chi tiết từng sản phẩm.
currencyservice Node.js Chuyển đổi số tiền giữa các loại tiền tệ. Sử dụng tỷ giá thực tế lấy từ Ngân hàng Trung ương Châu Âu (ECB). Đây là dịch vụ có QPS (Query per second) cao nhất.
paymentservice Node.js Thanh toán với thông tin thẻ tín dụng giả (mock) và số tiền nhất định, trả về ID giao dịch.
shippingservice Go Dự toán chi phí vận chuyển dựa trên giỏ hàng. Gửi hàng đến địa chỉ được cung cấp (mock).
emailservice Python Gửi email xác nhận đơn hàng cho người dùng (mock).
checkoutservice Go Lấy giỏ hàng người dùng, chuẩn bị đơn hàng, điều phối thanh toán, vận chuyển và thông báo qua email.
recommendationservice Python Đề xuất các sản phẩm khác dựa trên các mặt hàng trong giỏ hàng.
adservice Java Cung cấp quảng cáo văn bản dựa trên các từ ngữ ngữ cảnh được cung cấp.
loadgenerator Python/Locust Liên tục gửi các yêu cầu mô phỏng hành vi mua sắm thực tế của người dùng đến frontend.

Ta bắt đầu nhé 🚀🚀

Setup

Bài này ta sẽ làm ở local với Docker, nên yêu cầu là máy các bạn đã cài Docker nha

Tiếp theo ta clone project từ repo của Google Cloud về nhé: https://github.com/GoogleCloudPlatform/microservices-demo

git clone https://github.com/GoogleCloudPlatform/microservices-demo.git

Sau khi clone về ta có project như sau:

Ở đây ta thấy họ đã chuẩn bị sẵn cấu hình cho nhiều các deploy khác nhau: Kubernetes với manifest hoặc kustomize, Helm chart, terraform,...

Bài này ta làm ở local nên ta sẽ build trực tiếp từ src, ở trong đó thì họ đã tổ chức các service theo từng folder rõ ràng cho ta:

Ta bỏ qua service shoppingassistantservice, hiện tại (07/2024) họ chưa có doc cho việc sử dụng service này như nào

Và ở trong mỗi service họ đã có luôn cả Dockerfile cho ta luôn:

Quá toẹt vời, chứ ngồi mà đọc project xong tự viết Dockerfile cho hơn chục services chắc chớt 😜😜

Dockerize lần một

Ở lần đầu ta sẽ dockerize tất cả các service mà không cần gọi tới service khác, bao gồm 7 service: ad, productcatalog, cart, shipping, currency, payment, email

Ta bắt đầu với adservice trước nhé, ta mở terminal ở folder src/adservice:

docker build -t adservice .

Chờ một tí thấy như sau là oke rồi:

Tiếp theo tới productcatalogservice, tương tự vẫn mở terminal ở folder src/productcatalogservice và chạy:

docker build -t productcatalogservice .

Tiếp theo tới cartservice, vì Dockerfile của service này nằm trong 1 folder src nữa:

Nên ta phải mở terminal ở đúng folder nhé src/cartservice/src:

docker build -t cartservice .

Tiếp theo tới các service còn lại, cái này mình làm nhanh, các bạn nhớ phải mở terminal ở đúng folder rồi mới chạy build nhé:

# src/shippingservice
docker build -t shippingservice . # src/currencyservice
docker build -t currencyservice . # src/paymentservice
docker build -t paymentservice . # src/emailservice
docker build -t emailservice .

Vì tất cả các service đã được người ta viết sẵn Dockerfile hết rồi nên ta chỉ việc build lại thôi 😁

Sau khi build xong tất cả thì ta chạy lên xem có lỗi lầm gì không nhé.

Ở root folder project ta tạo file docker-compose.yml với nội dung như sau:

services: adservice: image: adservice productcatalogservice: image: productcatalogservice cartservice: image: cartservice environment: - REDIS_ADDR=redis-cart:6379 depends_on: - redis-cart redis-cart: image: redis:6-alpine shippingservice: image: shippingservice currencyservice: image: currencyservice paymentservice: image: paymentservice emailservice: image: emailservice

Ở trên ta sẽ chạy tất cả các service mà ta vừa build lên, bao gồm cả redis, chú ý rằng dựa vào diagram:

Ta thấy rằng cuối cùng chỉ cần frontend là cần map port ra ngoài vì user sẽ gọi vào từ đó, còn lại tất cả các service khác sẽ giao tiếp container->container bên trogn Docker luôn

Ở trên với service cartservice ta cần set biến môi trường REDIS_ADDR=redis-cart:6379 nó là địa chỉ của redis, mình biết biến này là vì xem ở file manifest K8S kubernetes-manifests/cartservice.yml 😆

Giờ ta chạy lên xem thế nào nhé:

docker compose up -d

Sau đó ta check xem các service đã Up chưa:

docker compose ps

Thì thấy kết quả như sau:

Ủa ở đây sao lại có mỗi 5 service Up nhỉ???? 🙄🙄

Trong khi ở docker-compose.yml ta có tất cả 8 services (kể cả redis), tức là ở đây ta thiếu 3 services: paymentservice, currencyservice, cartservice

Giờ ta sẽ check logs các service bị lỗi xem như nào nhé:

docker compose logs paymentservice

Lỗi: server must be bound in order to start

Lạ nhỉ??? 🤨🤨

Check code của paymentservice/server.js thì lỗi trả về từ GRPC, lọ mọ search Google thì thấy được issue này: https://github.com/grpc/grpc-node/issues/1404, có vẻ là bị lỗi IP port gì đó

Mở file manifest Kubernetes để hóng xem khi deploy với K8S thì họ có làm gì thêm không:

# kubernetes-manifests/paymentservice.yaml ...
env:
- name: PORT value: "50051"
- name: DISABLE_PROFILER value: "1"

Ầu, thì ra họ phải set PORT cho paymentservice, bên cạnh đó họ cũng có DISABLE_PROFILER luôn, vậy thì ta cứ follow và thêm vào các biến môi trường giống vậy nhé. Ta sửa lại docker-compose.yml như sau:

services: adservice: image: adservice environment: - PORT=9555 productcatalogservice: image: productcatalogservice environment: - PORT=3550 - DISABLE_PROFILER=1 cartservice: image: cartservice environment: - REDIS_ADDR=redis-cart:6379 depends_on: - redis-cart redis-cart: image: redis:6-alpine shippingservice: image: shippingservice environment: - PORT=50051 - DISABLE_PROFILER=1 currencyservice: image: currencyservice environment: - PORT=7000 - DISABLE_PROFILER=1 paymentservice: image: paymentservice environment: - PORT=50051 - DISABLE_PROFILER=1 emailservice: image: emailservice environment: - PORT=8080 - DISABLE_PROFILER=1

Ở trên ta cần check lại từng service một xem chúng cần biến môi trường gì, bên Kubernetes có biến nào ta thêm hết vào nhé 😁

Sau đó ta restart lại project:

docker compose down
docker compose up -d

Sau đó ta lại tiếp tục kiểm tra xem các service đã Up hết chưa:

docker compose ps

Các bạn tự làm phần này nhé, kiểm tra xem đủ 8 services chưa nhé, đến bước này là phải OK rồi đó, trừ các bạn dùng Macbook Apple Silicon chip (chip M) 😢

Với Macbook Apple chip

Nếu các bạn dùng Macbook Apple chip, thì ở bước này ta khi ta chạy docker compose ps, ta mới thấy chỉ có 7 services Up:

Thiếu mất một đó là cartservice, check logs ta thấy như sau:

docker compose logs cartservice

Search google một chút ra đầy kết quả, lí do là vì khả năng tương thích của project C# (dotnet) trên Apple Chip, vì apple chip họ dùng architecture khác (arm), trong khi thường sẽ là amd

Ta có thể check architecture hệ điều hành của chúng ta với command sau:

arch -->>>
arm64

Vậy giờ thử chạy cartservice với architecture amd xem, ta update docker-compose.yml cho cartservice như sau:

 cartservice: image: cartservice platform: linux/amd64 # ==> thêm vào environment: - REDIS_ADDR=redis-cart:6379 depends_on: - redis-cart

Sau đó ta restart lại project:

docker compose down
docker compose up -d

Ta lại thấy lỗi khác 😭😭:

Lí do là vì ta muốn chạy image cartservice với platform (architecture) khác, trong khi ở local ta không có image được build với platform như vậy nên Docker nó fallback tìm trên Dockerhub và không thấy, do vậy ta cần update Dockerfile của cartservice như sau:

FROM --platform=amd64 mcr.microsoft.com/dotnet/sdk:8.0.302-noble@sha256:bd836d1c4a19860ee61d1202b82561f0c750edb7a635443cb001042b71d79569 as builder
WORKDIR /app
COPY cartservice.csproj .
RUN dotnet restore cartservice.csproj \ -r linux-x64
COPY . .
RUN dotnet publish cartservice.csproj \ -p:PublishSingleFile=true \ -r linux-x64 \ --self-contained true \ -p:PublishTrimmed=true \ -p:TrimMode=full \ -c release \ -o /cartservice # https://mcr.microsoft.com/product/dotnet/runtime-deps
FROM --platform=amd64 mcr.microsoft.com/dotnet/runtime-deps:8.0.6-noble-chiseled@sha256:55d6e41f2e7687c597daa4fdca997b07beb3e23b6283729e19bb8ceb272def1a WORKDIR /app
COPY --from=builder /cartservice .
EXPOSE 7070
ENV DOTNET_EnableDiagnostics=0 \ ASPNETCORE_HTTP_PORTS=7070
USER 1000
ENTRYPOINT ["/app/cartservice"]

Ở trê các bạn chú ý mình đã thêm --platform=amd64 vào 2 chỗ có FROM.

Sau đó ta build lại image:

docker build -t cartservice:v1 .

Ở trên mình thêm tag v1 cho khác tránh nhầm lẫn

Nhưng lại có lỗi khác đó là build rất lâu, mãi chưa xong 😰😰:

Bị treo luôn ở đoạn RUN dotnet restore....

Lại lọ mọ search Google, mò một lúc thì tìm ra là có lẽ ta cần thêm ENV DOTNET_EnableWriteXorExecute=0, thôi thì lại sửa Dockerfile tiếp:

FROM --platform=amd64 mcr.microsoft.com/dotnet/sdk:8.0.302-noble@sha256:bd836d1c4a19860ee61d1202b82561f0c750edb7a635443cb001042b71d79569 as builder
ENV DOTNET_EnableWriteXorExecute=0
WORKDIR /app
COPY cartservice.csproj .
RUN dotnet restore cartservice.csproj \ -r linux-x64
COPY . .
RUN dotnet publish cartservice.csproj \ -p:PublishSingleFile=true \ -r linux-x64 \ --self-contained true \ -p:PublishTrimmed=true \ -p:TrimMode=full \ -c release \ -o /cartservice # https://mcr.microsoft.com/product/dotnet/runtime-deps
FROM --platform=amd64 mcr.microsoft.com/dotnet/runtime-deps:8.0.6-noble-chiseled@sha256:55d6e41f2e7687c597daa4fdca997b07beb3e23b6283729e19bb8ceb272def1a WORKDIR /app
COPY --from=builder /cartservice .
EXPOSE 7070
ENV DOTNET_EnableDiagnostics=0 \ ASPNETCORE_HTTP_PORTS=7070
USER 1000
ENTRYPOINT ["/app/cartservice"]

Ở trên ta đã thêm ENV DOTNET_EnableWriteXorExecute=0 vào stage builder (lần FROM đầu tiên)

Sau đó ta build lại image với tag mới v2:

docker build -t cartservice:v2 .

Oh ngon rồi:

Ta update cartservicedocker-compose.yml trước khi chạy lại nhé:

 cartservice: image: cartservice:v2 # ==> thêm vào platform: linux/amd64 # ==> thêm vào environment: - REDIS_ADDR=redis-cart:6379 depends_on: - redis-cart

Sau đó ta restart lại project:

docker compose down
docker compose up -d

Đến giờ thì ta đã có đủ tất cả 8 service đều Up, check logs của cartservice cũng oke rồi:

Dockerize lần hai

Lần này ta sẽ deploy 4 service còn lại, bao gồm: recommendation, frontend, checkout, loadgenerator

Cách làm vẫn tương tự, ta mở terminal ở từng service và build:

# src/recommendationservice
docker build -t recommendationservice . # src/frontend
docker build -t frontend . # src/checkoutservice
docker build -t checkoutservice . # src/loadgenerator
docker build -t loadgenerator .

Phần này thì các bạn tự chạy sẽ thấy OK nhé, nhưng vẫn trừ các bạn dùng Macbook Apple Chip 🤣🤣

Với các bạn dùng Apple Chip, khi build tới loadgenerator sẽ gặp lỗi:

Phần này các fix thì giống với cartservice ở trên, ta update lại Dockerfile của loadgenerator như sau:

FROM --platform=linux/amd64 python:3.12.4-slim@sha256:d3a32591680bdfd49da5773495730cf8afdb817e217435db66588b2c64db6d5e as base FROM base as builder COPY requirements.txt . RUN pip install --prefix="/install" -r requirements.txt FROM base WORKDIR /loadgen COPY --from=builder /install /usr/local # Add application code.
COPY locustfile.py . # enable gevent support in debugger
ENV GEVENT_SUPPORT=True ENTRYPOINT locust --host="http://${FRONTEND_ADDR}" --headless -u "${USERS:-10}" 2>&1

Ở trên dòng FROM đầu tiên ta thêm vào --platform=linux/amd64, chú ý rằng ta không cần làm vậy với 2 dòng FROM bên dưới, vì 2 cái FROM bên dưới chúng FROM trực tiếp từ base rồi (là dòng đầu tiên)

Sau khi update thì ta build lại loadgenerator (ta dùng tag v1 cho khác nhé):

docker build -t loadgenerator:v1 .

Oke ngon rồi:

Mệt với Apple chip quá 😂😂

Sau khi đã build xong các service ta update lại docker-compose.yml và thêm tất cả các service vào:

services: adservice: image: adservice environment: - PORT=9555 productcatalogservice: image: productcatalogservice environment: - PORT=3550 - DISABLE_PROFILER=1 cartservice: image: cartservice:v2 # ==> thêm vào platform: linux/amd64 # ==> thêm vào environment: - REDIS_ADDR=redis-cart:6379 depends_on: - redis-cart redis-cart: image: redis:6-alpine shippingservice: image: shippingservice environment: - PORT=50051 - DISABLE_PROFILER=1 currencyservice: image: currencyservice environment: - PORT=7000 - DISABLE_PROFILER=1 paymentservice: image: paymentservice environment: - PORT=50051 - DISABLE_PROFILER=1 emailservice: image: emailservice environment: - PORT=8080 - DISABLE_PROFILER=1 # --->> Thêm vào từ đây recommendationservice: image: recommendationservice environment: - PORT=8080 - PRODUCT_CATALOG_SERVICE_ADDR=productcatalogservice:3550 - DISABLE_PROFILER=1 depends_on: - productcatalogservice checkoutservice: image: checkoutservice environment: - PORT=5050 - PRODUCT_CATALOG_SERVICE_ADDR=productcatalogservice:3550 - SHIPPING_SERVICE_ADDR=shippingservice:50051 - PAYMENT_SERVICE_ADDR=paymentservice:50051 - EMAIL_SERVICE_ADDR=emailservice:8080 - CURRENCY_SERVICE_ADDR=currencyservice:7000 - CART_SERVICE_ADDR=cartservice:7070 depends_on: - productcatalogservice - shippingservice - paymentservice - emailservice - currencyservice - cartservice frontend: image: frontend ports: - "8000:8080" environment: - PORT=8080 - PRODUCT_CATALOG_SERVICE_ADDR=productcatalogservice:3550 - CURRENCY_SERVICE_ADDR=currencyservice:7000 - CART_SERVICE_ADDR=cartservice:7070 - RECOMMENDATION_SERVICE_ADDR=recommendationservice:8080 - SHIPPING_SERVICE_ADDR=shippingservice:50051 - CHECKOUT_SERVICE_ADDR=checkoutservice:5050 - AD_SERVICE_ADDR=adservice:9555 - ENABLE_PROFILER=0 - SHOPPING_ASSISTANT_SERVICE_ADDR=shoppingassistantservice:8080 depends_on: - productcatalogservice - currencyservice - cartservice - recommendationservice - shippingservice - checkoutservice - adservice loadgenerator: image: loadgenerator:v1 platform: linux/amd64 environment: - FRONTEND_ADDR=frontend:8080 depends_on: - frontend

Chú ý rằng ở trên các biến môi trường mình xem từ các file manifest Kubernetes của các service tương ứng và thêm vào, mình có thêm depends_on thể hiện sự phụ thuộc giữa các service cho đúng với diagram, như vậy thì khi Docker start container nó sẽ start các service độc lập trước, sau đó tới các service phụ thuộc

Chú ý rằng ở service frontend mình phải thêm biến SHOPPING_ASSISTANT_SERVICE_ADDR, vì trong code họ yêu cầu cái đó, nhưng thực tế ta không cần service đó để chạy

Giờ ta restart lại project nhé:

docker compose down docker compose up -d

Pòm pòm chíu chíu 🥳🥳:

App của chúng ta lên rồi, các bạn thoải mái test xem tất cả flow có gì lỗi không nhé:

Với Macbook Apple Chip

Vâng, một lần nữa, lại là Apple Chip 🤣🤣

nếu ta thử restart lại project:

docker compose down docker compose up -d

Thì rất có thể ta sẽ gặp lỗi:

Lại là cartservice, cái service dotnet củ chuối này 🤨🤨

Check log ta thấy như sau:

20240706-123737.jpeg

Sau khi search một vòng Google thì ta sẽ hiểu ra thì đây là một lỗi khá phổ biến của project C#(dotnet) khi chạy trên arm.

Tìm mãi không ra được solution cụ thể, tắt laptop khởi động lại thì có khi được 1-2 lần lại bị.

May quá tìm ra PR này: https://github.com/GoogleCloudPlatform/microservices-demo/pull/2266/files#diff-c9094dcf2dd2b5e3bb57d27631699d50e63b9bfb3aa3665db826e031b0ab9b4c

ý tưởng của họ là update Dockerfile để build project target tới architecture khác linux-musl-arm64 (alpine + arm64), dùng runtime identifier (RID):

  • linux: hệ điều hành target là Linux
  • musl: Thư viện C là musl, thường được dùng trên bản phân phối Alpine.
  • arm64: architecture la ARM64 (cũng được biết đến là AArch64), tương thích với Appl M1/M2/... chips và các platform ARM64 khác.

Giờ ta sửa lại Dockerfile của cartservice như sau nhé:

FROM mcr.microsoft.com/dotnet/sdk:8.0 as builder
WORKDIR /app
COPY cartservice.csproj .
RUN dotnet restore cartservice.csproj \ -r linux-musl-arm64
COPY . .
RUN dotnet publish cartservice.csproj \ -p:PublishSingleFile=true \ -r linux-musl-arm64 \ --self-contained true \ -p:PublishTrimmed=true \ -p:TrimMode=full \ -c release \ -o /cartservice # https://mcr.microsoft.com/product/dotnet/runtime-deps
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-alpine3.18-arm64v8 WORKDIR /app
COPY --from=builder /cartservice .
EXPOSE 7070
ENV DOTNET_EnableDiagnostics=0 \ ASPNETCORE_HTTP_PORTS=7070
USER 1000
ENTRYPOINT ["/app/cartservice"]

Ở trên các bạn để ý rằng:

  • ta không cần tới biến môi trường ENV DOTNET_EnableWriteXorExecute=0
  • ở stage builder ta dùng linux-musl-arm64
  • ở cái FROM thứ 2 thì ta dùng image runtime-deps:8.0-alpine3.18-arm64

Giờ ta build lại image cartservice với tag v3 nhé:

docker build -t cartservice:v3 .

Sau đó sửa lại cartservicedocker-compose.yml

 cartservice: image: cartservice:v3 # ==> update environment: - REDIS_ADDR=redis-cart:6379 depends_on: - redis-cart

Chú ý rằng ta đã bỏ đi dòng platform: linux/amd64

Cuối cùng chạy lên ta sẽ thấy OK nhé. phewwwwww Apple Chip mệt quá ta 😅

Tổng hợp và kết bài

Như các bạn thấy, dù bài này Dockerfile họ đã viết sẵn cho chúng ta rồi nhưng khi chạy lên tuỳ vào môi trường của ta là gì nó còn có thể phát sinh lỗi và ta phải mò thêm.

Nhìn chung đây là ví dụ khá là trực quan demo việc deploy microservices với Docker như thế nào. Việc vẽ được, hiểu được architecture trước giúp quá trình làm việc của ta mượt hơn nhiều, ta biết được service nào phụ thuộc vào service khác, service nào không, từ đó đưa ra kế hoạch deploy cho phù hợp.

Chúc các bạn cuối tuần vui vẻ, hẹn gặp lại các bạn ở những bài sau

Bình luận

Bài viết tương tự

- vừa được xem lúc

STACKDRIVER - GETTING STARTED

1. Overview.

0 0 45

- vừa được xem lúc

Deploying A Containerized Web Application On Kubernetes

1. Overview. Kubernetes is an open source project (available on kubernetes.io) which can run on many different environments, from laptops to high-availability multi-node clusters; from public clouds to on-premise deployments; from virtual machines to bare metal.

0 0 42

- vừa được xem lúc

Thực hành K8S trên Google Cloud

Kubernetes (K8S) trở nên quá phổ biến ở thời điểm hiện tại, ai cũng nói về nó. Trong bài hôm nay mình sẽ không đi quá nhiều vào các định nghĩa, mà đi thẳng vào thực tế để mọi người dễ hình dung.

0 0 29

- vừa được xem lúc

Giới thiệu về Bigquery trong Google Cloud Platform

Nếu đã làm việc nhiều với Google Cloud Platform chắc hẳn các bạn không còn xa lạ gì với cái tên Bigquery. Trong bài viết này, mình sẽ giới thiệu qua về Bigquery nhưng hãy cân nhắc về điểm mạnh cũng nh

0 0 37

- vừa được xem lúc

Làm việc tại nhà an toàn hơn với VPN của riêng bạn - Hoàn toàn miễn phí

Mở đầu. Lại một đợt dịch mới quay lại với nhiều tin tức xấu hơn sau mỗi lần bùng phát, cũng vì thế là công việc WORK FROM HOME lại quay trở lại với rất nhiều ngành nghề và đặc biệt là anh em IT.

0 0 40

- vừa được xem lúc

Hướng dẫn kéo dài thời gian sử dụng Google Cloud miễn phí

1. Mở đầu.

0 0 27