Sudah waktunya untuk menangani wadah
Pertama-tama, kami menggunakan gambar Linux Alpine terbaru. Linux Alpine adalah distribusi Linux ringan yang dirancang dan dioptimalkan untuk menjalankan aplikasi web di Docker. Dengan kata lain, Linux Alpine memiliki cukup dependensi dan fungsionalitas untuk menjalankan sebagian besar aplikasi. Ini berarti ukuran gambar sekitar 8 MB!
Dibandingkan dengan, katakanlah ... mesin virtual Ubuntu dengan kapasitas sekitar 1 GB, itu sebabnya gambar Docker menjadi lebih alami untuk layanan microser dan cloud computing.
Jadi, sekarang saya berharap Anda melihat nilai dalam kontainerisasi, dan kita bisa mulai "Dockerising" layanan pertama kami. Ayo buat Dockerfile
$ touch consignment-service / Dockerfile .
Bagian pertamaRepositori EwanValentine asliArtikel asliDi Dockerfile, tambahkan berikut ini:
FROM alpine:latest RUN mkdir /app WORKDIR /app ADD consignment-service /app/consignment-service CMD ["./consignment-service"]
Lalu kami membuat direktori baru untuk meng-host aplikasi kami. Kemudian kami menambahkan biner terkompilasi kami ke wadah Docker kami dan menjalankannya.
Sekarang, mari kita perbarui catatan pembuatan Makefile kami untuk membuat gambar Docker.
build: ... GOOS=linux GOARCH=amd64 go build docker build -t consignment .
Kami menambahkan dua langkah lagi, dan saya ingin menjelaskannya lebih terinci. Pertama-tama, kami membuat biner Go kami. Namun, Anda akan melihat dua variabel lingkungan sebelum kami menjalankan $ go build. GOOS dan GOARCH memungkinkan Anda mengkompilasi silang biner Anda untuk sistem operasi lain. Karena saya mengembangkan untuk Macbook, saya tidak bisa mengkompilasi go executable dan kemudian menjalankannya dalam wadah Docker yang menggunakan Linux. Biner akan benar-benar tidak berarti dalam wadah Docker Anda dan itu akan menimbulkan kesalahan.
Langkah kedua yang saya tambahkan adalah proses pembangunan buruh pelabuhan. Docker akan membaca Dockerfile Anda dan membuat gambar bernama layanan-konsinyasi, titik menunjukkan jalur direktori, jadi di sini kami hanya ingin proses build untuk melihat direktori saat ini.
Saya akan menambahkan entri baru ke Makefile kami:
run: docker run -p 50051:50051 shippy-service-consignment
Di sini kami meluncurkan gambar buruh pelabuhan kami dengan membuka port 50051. Karena Docker beroperasi pada lapisan jaringan yang terpisah, Anda perlu mengarahkan ulang port tersebut. Misalnya, jika Anda ingin memulai layanan ini pada port 8080, Anda harus mengubah argumen -p ke 8080: 50051. Anda juga dapat menjalankan kontainer di latar belakang dengan menyertakan flag -d. Misalnya,
buruh pelabuhan menjalankan -d -p 50051: 50051-layanan konsinyasi .
Jalankan
$ make run , lalu di panel terminal yang terpisah lagi
$ pergi jalankan main.go dan periksa apakah masih berfungsi.
Saat Anda menjalankan $ docker build, Anda menyematkan kode dan runtime di gambar. Gambar Docker adalah gambar portabel dari lingkungan Anda dan dependensinya. Anda dapat berbagi gambar Docker dengan mempostingnya ke Docker Hub. Yang mirip dengan npm atau repositori yum untuk gambar buruh pelabuhan. Ketika Anda mendefinisikan FROM di Dockerfile Anda, Anda memberi tahu Docker untuk menarik gambar ini dari repositori Docker untuk digunakan sebagai basis. Anda kemudian dapat memperluas dan mendefinisikan kembali bagian-bagian dari file dasar ini, mendefinisikannya kembali sesuai keinginan. Kami tidak akan mempublikasikan gambar buruh pelabuhan kami, tetapi merasa bebas untuk menelusuri repositori buruh pelabuhan dan perhatikan bahwa hampir semua perangkat lunak telah dikemas dalam wadah. Beberapa hal yang benar-benar luar biasa merosot.
Setiap iklan di Dockerfile di-cache saat pertama kali dibuat. Ini menghilangkan kebutuhan untuk membangun kembali seluruh runtime setiap kali Anda membuat perubahan. Docker cukup pintar untuk mengetahui detail mana yang telah berubah dan mana yang perlu dibangun kembali. Ini membuat proses pembuatannya sangat cepat.
Cukup tentang wadahnya! Mari kita kembali ke kode kita.
Saat membuat layanan gRPC, ada banyak kode standar untuk membuat koneksi, dan Anda perlu melakukan hard-code lokasi alamat layanan di klien atau layanan lain sehingga dapat terhubung ke sana. Ini sulit karena ketika Anda memulai layanan di cloud, mereka mungkin tidak menggunakan host yang sama, atau alamat atau ip dapat berubah setelah layanan dipekerjakan kembali.
Di sinilah layanan penemuan berperan. Layanan penemuan memperbarui direktori semua layanan Anda dan lokasi mereka. Setiap layanan terdaftar pada saat runtime dan tidak terdaftar di dekat. Setiap layanan kemudian diberi nama atau pengenal. Dengan demikian, bahkan jika itu mungkin memiliki alamat IP baru atau alamat host, asalkan nama layanan tetap sama, Anda tidak perlu memperbarui panggilan ke layanan ini dari layanan lain.
Sebagai aturan, ada banyak pendekatan untuk masalah ini, tetapi, seperti kebanyakan hal dalam pemrograman, jika seseorang telah mengatasi masalah ini, tidak masuk akal untuk menemukan kembali roda. @ Chuhnk (Asim Aslam), pencipta
Go-micro , memecahkan masalah ini dengan kejelasan yang fantastis dan kemudahan penggunaan. Dia seorang diri menghasilkan perangkat lunak yang fantastis. Tolong pertimbangkan untuk membantunya jika Anda menyukai apa yang Anda lihat!
Lakukan mikro
Go-micro adalah kerangka kerja layanan mikro yang kuat yang ditulis dalam Go, untuk digunakan, sebagian besar, dengan Go. Namun, Anda dapat menggunakan Sidecar untuk berinteraksi dengan bahasa lain.
Go-micro memiliki fitur yang berguna untuk membuat layanan microser di Go. Tetapi kita akan mulai dengan mungkin masalah yang paling umum yang dia selesaikan, dan ini adalah penemuan sebuah layanan.
Kami perlu membuat beberapa pembaruan untuk layanan kami agar dapat bekerja dengan go-micro. Go-micro terintegrasi sebagai plugin Protoc, dalam hal ini menggantikan plugin gRPC standar yang saat ini kami gunakan. Jadi, mari kita mulai dengan mengganti ini di Makefile kita.
Pastikan untuk menginstal dependensi go-mikro:
go get -u github.com/micro/protobuf/{proto,protoc-gen-go}
Perbarui Makefile kami untuk menggunakan plugin go-micro alih-alih plugin gRPC:
build: protoc -I. --go_out=plugins=micro:. \ proto/consignment/consignment.proto GOOS=linux GOARCH=amd64 go build docker build -t consignment . run: docker run -p 50051:50051 shippy-service-consignment
Sekarang kita perlu memperbarui shippy-service-consignment / main.go kita untuk menggunakan go-micro. Ini abstrak sebagian besar kode gRPC kami sebelumnya. Ini dengan mudah memproses pendaftaran dan mempercepat penulisan layanan.
shippy-service-consignment / main.go Perubahan utama di sini adalah cara kami membuat server gRPC kami, yang telah disarikan dengan rapi dari mico.NewService (), yang menangani pendaftaran layanan kami. Dan akhirnya, fungsi service.Run (), yang memproses koneksi itu sendiri. Seperti sebelumnya, kami mendaftarkan implementasi kami, tetapi kali ini dengan metode yang sedikit berbeda.
Perubahan terbesar kedua menyangkut metode layanan itu sendiri: argumen dan jenis respons sedikit dimodifikasi untuk menerima baik permintaan dan struktur respons sebagai argumen, dan sekarang hanya mengembalikan kesalahan. Dalam metode kami, kami mengatur respons yang masuk ke proses mikro.
Akhirnya, kami tidak lagi memprogram port. Go-micro harus dikonfigurasi menggunakan variabel lingkungan atau argumen baris perintah. Untuk mengatur alamat, gunakan MICRO_SERVER_ADDRESS =: 50051. Secara default, Micro menggunakan mdns (multicast dns) sebagai broker penemuan layanan untuk penggunaan lokal. Biasanya Anda tidak menggunakan mdns untuk menemukan layanan di lingkungan produksi, tetapi kami ingin menghindari menjalankan sesuatu seperti Konsul atau etcd secara lokal untuk pengujian. Lebih lanjut tentang ini nanti.
Mari perbarui Makefile kami untuk mencerminkan ini.
build: protoc -I. --go_out=plugins=micro:. \ proto/consignment/consignment.proto GOOS=linux GOARCH=amd64 go build docker build -t consignment . run: docker run -p 50051:50051 \ -e MICRO_SERVER_ADDRESS=:50051 \ shippy-service-consignment
-e adalah flag variabel lingkungan, memungkinkan Anda untuk mengirimkan variabel lingkungan ke wadah Docker Anda. Anda harus memiliki bendera untuk setiap variabel, misalnya -e ENV = pementasan -e DB_HOST = localhost, dll.
Sekarang, jika Anda menjalankan $ make run, Anda akan memiliki layanan Dockerised dengan penemuan layanan. Jadi, mari perbarui alat Cli kami untuk menggunakan ini.
konsinyasi-cli package main import ( "encoding/json" "io/ioutil" "log" "os" "context" pb "github.com/EwanValentine/shippy-service-consignment/proto/consignment" micro "github.com/micro/go-micro" ) const ( address = "localhost:50051" defaultFilename = "consignment.json" ) func parseFile(file string) (*pb.Consignment, error) { var consignment *pb.Consignment data, err := ioutil.ReadFile(file) if err != nil { return nil, err } json.Unmarshal(data, &consignment) return consignment, err } func main() { service := micro.NewService(micro.Name("shippy.cli.consignment")) service.Init() client := pb.NewShippingServiceClient("shippy.service.consignment", service.Client())
Di sini, kami mengimpor perpustakaan go-micro untuk membuat klien dan mengganti kode koneksi yang ada dengan kode klien go-mikro, yang menggunakan izin layanan alih-alih langsung terhubung ke alamat.
Namun, jika Anda menjalankan ini, itu tidak akan berhasil. Ini karena kami sekarang meluncurkan layanan kami di wadah Docker, yang memiliki mdns sendiri, terpisah dari host mdns yang saat ini kami gunakan. Cara termudah untuk memperbaikinya adalah memastikan bahwa baik layanan dan klien berjalan di dockerland, sehingga keduanya bekerja pada host yang sama dan menggunakan lapisan jaringan yang sama. Jadi, mari kita buat make konsinyasi-cli / Makefile dan buat beberapa entri.
build: GOOS=linux GOARCH=amd64 go build docker build -t shippy-cli-consignment . run: docker run shippy-cli-consignment
Seperti sebelumnya, kami ingin membangun biner untuk Linux. Saat kami meluncurkan gambar buruh pelabuhan kami, kami ingin meneruskan variabel lingkungan untuk memberikan perintah go-micro untuk menggunakan mdns.
Sekarang mari kita buat Dockerfile untuk alat CLI kami:
FROM alpine:latest RUN mkdir -p /app WORKDIR /app ADD consignment.json /app/consignment.json ADD consignment-cli /app/consignment-cli CMD ["./shippy-cli-consignment"]
Ini sangat mirip dengan Dockerfile layanan kami, kecuali bahwa itu juga mengekstrak file data json kami.
Sekarang ketika Anda menjalankan $ make run di shippy-cli-cli-consignment Anda, Anda akan melihat Created: true, sama seperti sebelumnya.
Sekarang, sepertinya saatnya untuk melihat fitur Docker baru: pembuatan multi-tahap. Ini memungkinkan kita untuk menggunakan beberapa gambar Docker dalam satu Dockerfile.
Ini sangat berguna dalam kasus kami, karena kami dapat menggunakan satu gambar untuk membuat file biner kami dengan semua dependensi yang benar. Dan kemudian gunakan gambar kedua untuk meluncurkannya. Mari kita coba ini, saya akan meninggalkan komentar rinci bersama dengan kode:
layanan konsinyasi / Dockerfile # consignment-service/Dockerfile # golang, # . `as builder`, # , . FROM golang:alpine as builder RUN apk --no-cache add git # gopath WORKDIR /app/shippy-service-consignment # COPY . . RUN go mod download # , # Alpine. RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o shippy-service-consignment # FROM, # Docker . FROM alpine:latest # , - RUN apk --no-cache add ca-certificates # , . RUN mkdir /app WORKDIR /app # , , # `builder` # , # , , # . ! COPY --from=builder /app/shippy-service-consignment/shippy-service-consignment . # ! # # run time . CMD ["./shippy-service-consignment"]
Sekarang saya akan pindah ke file Docker lain dan mengambil pendekatan baru ini. Oh, dan jangan lupa menghapus $ go build dari Makefiles Anda!
Layanan kapal
Mari kita buat layanan kedua. Kami memiliki layanan (shippy-service-konsignment), yang berkaitan dengan koordinasi batch kontainer dengan kapal, yang paling cocok untuk batch ini. Untuk mencocokkan batch kami, kami harus mengirim berat dan jumlah kontainer ke layanan kapal baru kami, yang kemudian akan menemukan kapal yang mampu menangani batch ini.
Buat direktori baru di root
$ mkdir Anda kapal-layanan direktori, sekarang buat subdirektori untuk definisi layanan protobuf baru kami,
$ mkdir -p shippy-service-ship / proto / vessel . Sekarang mari kita buat file protobuf baru,
$ touch shippy-service-vessel / proto / vessel / vessel.proto .
Karena definisi protobuf memang merupakan inti dari desain perangkat lunak kami, mari kita mulai dengan itu.
kapal / kapal. foto // shippy-service-vessel/proto/vessel/vessel.proto syntax = "proto3"; package vessel; service VesselService { rpc FindAvailable(Specification) returns (Response) {} } message Vessel { string id = 1; int32 capacity = 2; int32 max_weight = 3; string name = 4; bool available = 5; string owner_id = 6; } message Specification { int32 capacity = 1; int32 max_weight = 2; } message Response { Vessel vessel = 1; repeated Vessel vessels = 2; }
Seperti yang Anda lihat, ini sangat mirip dengan layanan pertama kami. Kami membuat layanan dengan satu metode rpc yang disebut FindAvailable. Ini mengambil jenis Spesifikasi dan mengembalikan jenis Respons. Jenis Respon mengembalikan jenis Kapal atau beberapa kapal menggunakan bidang berulang.
Sekarang kita perlu membuat Makefile untuk menangani logika build dan skrip startup kita.
$ touch shippy-service-vessel / Makefile . Buka file ini dan tambahkan yang berikut:
// vessel-service/Makefile build: protoc -I. --go_out=plugins=micro:. \ proto/vessel/vessel.proto docker build -t shippy-service-vessel . run: docker run -p 50052:50051 -e MICRO_SERVER_ADDRESS=:50051 shippy-service-vessel
Ini hampir identik dengan Makefile pertama yang kami buat untuk layanan konsinyasi kami, namun perhatikan bahwa nama-nama layanan dan port telah sedikit berubah. Kami tidak dapat meluncurkan dua wadah dok pada port yang sama, jadi kami menggunakan penerusan port Dockers sehingga layanan ini mengalihkan dari 50051 ke 50052 di jaringan host.
Sekarang kita membutuhkan Dockerfile menggunakan format multi-tahap baru:
# vessel-service/Dockerfile FROM golang:alpine as builder RUN apk --no-cache add git WORKDIR /app/shippy-service-vessel COPY . . RUN go mod download RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o shippy-service-vessel FROM alpine:latest RUN apk --no-cache add ca-certificates RUN mkdir /app WORKDIR /app COPY --from=builder /app/shippy-service-vessel . CMD ["./shippy-service-vessel"]
Akhirnya, kita dapat menulis implementasi kita:
Sekarang mari kita beralih ke bagian yang menarik. Ketika kami membuat pengiriman, kami perlu mengubah layanan penanganan kargo kami untuk menghubungi layanan pencarian kapal, menemukan kapal dan memperbarui parameter ship_id dalam pengiriman yang dibuat:
shippy / konsinyasi-layanan / main.go package main import ( "context" "fmt" "log" "sync" pb "github.com/EwanValentine/shippy-service-consignment/proto/consignment" vesselProto "github.com/EwanValentine/shippy-service-vessel/proto/vessel" "github.com/micro/go-micro" ) const ( port = ":50051" ) type repository interface { Create(*pb.Consignment) (*pb.Consignment, error) GetAll() []*pb.Consignment }
Di sini kami membuat contoh klien untuk layanan kapal kami, yang memungkinkan kami untuk menggunakan nama layanan, yaitu shipy.service.vessel untuk memanggil layanan kapal sebagai klien dan berinteraksi dengan metodenya.
Dalam hal ini, hanya satu metode (FindAvailable). Kami mengirimkan berat batch bersama dengan jumlah kontainer yang ingin kami kirimkan, sebagai spesifikasi untuk layanan kapal. Yang mengembalikan kami sesuai dengan spesifikasi kapal ini.Perbarui file konsinyasi-cli / consignment.json, hapus kode_kapal, karena kami ingin mengonfirmasi bahwa layanan pencarian kapal kami berfungsi. Selain itu, mari tambahkan beberapa wadah lagi dan tambah beratnya. Sebagai contoh:
{ "description": " ", "weight": 55000, "containers": [ { "customer_id": "_001", "user_id": "_001", "origin": "--" }, { "customer_id": "_002", "user_id": "_001", "origin": "" }, { "customer_id": "_003", "user_id": "_001", "origin": "" } ] }
Sekarang jalankan $ make build && make run dalam pengiriman-cli. Anda harus melihat jawaban dengan daftar barang yang dibuat. Di pesta Anda, Anda akan melihat bahwa parameter vessel_id diatur.Jadi, kami memiliki dua microservices yang saling berhubungan dan antarmuka baris perintah!Di bagian selanjutnya dari seri ini, kami akan mempertimbangkan menyimpan beberapa data ini menggunakan MongoDB. Kami juga akan menambahkan layanan ketiga dan menggunakan komposisi buruh pelabuhan untuk mengelola ekosistem kontainer kami yang tumbuh secara lokal.Bagian IRepositori EwanValentine Asli