justforfunc #12: a Text to Speech server with gRPC and Kubernetes

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

These are great. Really enjoying them. I hope they keep coming.

👍︎︎ 10 👤︎︎ u/ZnVja3JlZGRpdA 📅︎︎ May 18 2017 🗫︎ replies

Very interesting and well explained as always, thanks /u/campoy :)

👍︎︎ 7 👤︎︎ u/feddasch 📅︎︎ May 18 2017 🗫︎ replies

Inspired by your video I created a bindings for flite https://github.com/gen2brain/flite-go . It only has a couple of basic public functions, but voice can be chosen.

👍︎︎ 3 👤︎︎ u/gen2brain 📅︎︎ May 18 2017 🗫︎ replies
Captions
hi I am Francis campoy and this is just a funk so welcome to editor number 12 just for fun today as I've said before we're going to be working with g RT c and g RP c is a cool way of making different processes communicate g RPC actually stands for g RPC remote procedure call and basically it's just substitute as substitute for things like the rest instead of using Jason uses protocol buffers instead of so using HTTP it is actually a built-in protocol that you decide on with it you can call the functions whatever you want and it works over HTTP to has a lot of benefits but I will not talk too much about why G RPC is cool you can learn about it on GRP see that IO instead what I'm going to do is I'm going to build something with it what am I going to build I'm going to be able to command say I don't know if you've seen it but if you run say hello friends at least on Mac you will get a little bit hello friends what I want to do is exactly the same but build completely go now to do this normally you're going to need to either have a library that does this the transformation from text to speech or but in go and I can define any or have some package that you can install and that's what we're going to be doing we're going to install a package that does this it's called a flight or flight not very sure and we're going to solve this on the back end now to communicate from our plan our command line client to our back end we're going to be using G RPC so that's the whole thing we're going to build but we're going to start first by getting that back and working even just a little bit some time let's get started ok so as always I start with a completely empty directory and I'm going to have three directories I'm going to have the client I'm going to have the backend and I'm going to have also one for the API which is actually the defeating of the API which is shared across the client and the server so let's start with the back end in that back end we're going to have what do we want to have well I think that the best place to start here is we want to run something in linux using this package called slide let me find it for you so it's this package there is available alpine flight and this is a beautiful webpage that definitely not the most modern web page I've ever seen but basically what it does is it allows you to do synthesis of text into speech and it's completely bringing C which is for portability as a gopher I find that sentence slightly funny and we could use C go any solid but instead of doing that what I'm going to do is I'm going to store this in an alpine container and then use xx to call that binary from go so let's say first installing the container itself so we're going to create a docker file and that docker phone when I start from outline and I will run apk which is a Alpine equivalent of apt-get if you don't know what that is it's basically a way to install packages so we're going to update and apk add thing it's called flight and with that we should be able to now relatively easily let's try docker bill - T I'm going to go it cowboy safe for now so bill this I'm not on the back end okay boom that was fast because it was cached and neither do docker run - - R M - can't I say and I run flight ok that that is the command we're going to use you see now it's it's working I want to try it so let's see actually the help what this says so - these for the text and - oh it for the wet file so if we run - the hello and - Oh output dot valve or waive the know how to pronounce it please work but where did that spell end up ended up well it ended inside of the container - we just ate it so let's say that let's create one directory and I'm going to map that directory inside of the container so when we write we write into that container into a directory and we will be able to keep the file itself so let's do docker run - - RM so it's failure at the end - v4 volumes so I'm going to do data so slash data into data I'm going to set the working directory to data to actually let me add data there and then we're going to do flight hello and output done Wow and hopefully when I run this we should see oh of course I need to say that we running campoy campus a cool and we got that output by there that I cannot be flick of course that why file but I should be able to do a play of the data output hello and it doesn't sound amazing but it works so hello I'm going to be using that package cool okay our next step is going to be to do something really similar but I'm going to call that same command from a go program but go program the only thing you will do will be to actually call the binary just once pretty simple let's do that so I'm going to start by creating a min go go and that package will is a executive command and executive command receives the name of the binary that you want to run in this case is slide the arguments let's say let's actually pass OS X of one and this could fail let's find so and then - OH output dot Java and this will give us a command we want to see the output of that command so I will set standard output to OS standard output and standard error to OS standard error and finally we will actually run it and if that fails we'll do a log fatal of better cool so now if I try to run that binary - shooting network because here it will say well ok it will say I don't know what slight is a binary executable file not falling back which is true because we have not installed it on my machine but if we add it to docker file we should be able to do this now how do we add this binary to docker file there's a couple ways one of the ways is to install the go compiler into docker file and then compile the go add the main logo and compile it from there and that works especially if you are doing multistage docker files this is something that you could do but actually in my case I find it much easier to simply use a make file so what I'm going to do is I'm going to have a make file that allows me to say when you build you're going to cross compile the go code that you find in this in this package to Linux so go S or goose is Linux and go build - Oh app so that will send the result of building package into the binary app then I'm going to do docker build - de Campo say of this and then finally I'm going to remove that binary and here I can add app to slash app and then say that the entry point of this docker container is slash app so now by default rather than running the binary that we have before flight we will run app and we will pass all the rest of parameters that we pass in the docker run line as parameters to the apps command so let's do make built hmm the make files supposed to be inside of the backend okay make built we cross compile the application we build a binary in that we remove the binary again because we don't need that and I we do docker run - - R + - v data data data can poi say and we're going to say hello we should still work and we should have this here and actually let me try something different by saying hello there and then try to play that binary that we generate that output closer cool so this works you nice so now we're able to have a go program that runs flight from inside of docker container what's the next step making this into a G RPC server and to do that first we need to understand what G RPC is in how it works okay so G RPC basically the way it works is that you define the surface of your API kind of like you could do with swagger or open API specification same thing or waddle or wiggle or all of those different languages that allow you to describe an API what do you have in that description well you have the methods that out that you're allowed to go and what parameters they have and also some options will actually go with something really really simple to start with so what I'm going to do is I'm going to create a new API directory and that directory will contain a say dot proto that product is the product the protocol buffer definition of our G IPC API and that might sound a little bit complicated now but don't work is actually incredibly simple so I'm going to create any directory going to call it API that's going to be right here and in there I'm going to create say dot proto now all protocol buffers files start always with the syntax there's three different versions of the protocol buffer I recommend using just proto 3 which is the simplest one it's interesting how from 402 to pro 3 rather than adding things we actually removed a bunch of them which makes the language much easier to understand so syntax is code or 3 and then you need to say what package you're creating let's say let's call the package say and then you need to define a service I'm going to call that service text-to-speech because it is what the service does and instead of a service you have a series of our pcs which is basically endpoints so I'm going to say have the RPC say and these given some text returns some speech and then there's no options so you can use this empty body you could also use semicolon I prefer this one personally ok so now we need to define what text and speech are and there's simply messages so message text is something that has a string text let's call it text actually and then you need to give one number and this number is very important because these actually numbered that identifies the field because the text names will not be the field names will not be sent in the into the wire when you compile protocol buffer you end up with something very compact which is binary and it allows you to do versioning through these definitions so I do need to do is you need to share these definitions with the client and the user etc it is different to rest because with West you use JSON and no matter what no matter what methods you sending in JSON you should be able to decode something with protocol buffers if you don't have this descriptor you're not able to the code you don't know what to look for so it's a little bit different but it's way faster you gain performance and it's also very nice to use personally I rather use protocol buffers with G RPC then you Jason with swagger but maybe that's a personal thing okay so we have our message text and then also we have our message speech and I'm going to say that this is byte audio and that's it this is the description of my whole API it's not super complicated and now that we have this we can generate code for this and we're going to get a code for two sides we're going to generate code for the client and for the server but both are generated with one single command that command that use that utility it's called proto C proto compiler and we're going to need to pass some parameters to say by the way this is proto C to generate go code so the way this works is and I'm actually going to write it directly into a make file because it's kind of long thing so I read the other here it's Prada see what to include we're going to include this file this world includes our save the proto then we're going to add go out which is not an order but how to say that we want an output of go code and we're going to say that we're going to be using the plugins GRP c and generate everything into this column sorry that is like this so proto c include this directory save the product because that's the father we want to compile and - - go out to generate go code and the plugin that we're going to be using AG RPC and the output is also dot cool so if we go to the API and we do make built this doesn't work oh no it did work oh and it generate this code right here and the code contains a bunch of different things it's not important to understand all of it but the cool thing is that you can do go doc and see what are the things that are defined so you have text and switch both are types so type text type pad type speech and then we have registered text-to-speech server and also need text to speech button so you have both sides all the thing and even more important you also have the text-to-speech server which is an interface and this is where we're going to get now because in order to call registered text-to-speech server you need to pass a type that satisfies that text-to-speech server and the text-to-speech server if we do text-to-speech server is an interface that has one method say that given a context and some text returns some speech in an error so that is the engine that is the method that we need to add to our server in order to be at G RPC server for this specific service let's do that ok so we're going to go back to main logo and we're going to change this code so rather than being just something that comes once a that flight command it's going to call that command slide every single time that there's a G RPC request coming so for now I'm going to keep this here for later let me comment it out and now what we're going to do is our function main will serve G RPC and this is kind of similar to HTTP right you know HTTP listen answers you need app or do you need handlers and stuff like that this is exactly the same just a little bit different so we're going to need that port and I'm going to define that as a flag so I'm going to say that is P and the default value will be 8080 and poor to listen to will need to parse the flag and then we're going to create a listener that listens on that port to do that we do net dub listen TCP there you go so now that will list that will give us a listener that listens on that IP port the IP and not giving any so it's localhost and that will be a listener and an error if there is a meal then I'm going to be using log rose today because why not I really like it it's a very nice logging to fatal F could not listen to port that thing and there's the error so that is port actually that should be port like this port and error that's where we're going to be listening to but now that we have how to listen what do we do with it and to do that we're going to create an eg RPC server so for that it's simply G RPC dot new server that will give us a server and that server we're going to use it to call a function that is one of the functions that was also generated from the G IPC protocol buffer definition so just for fun that's a bunch of things it's actually say G RPC and API whoops and let's call it PB for protocol buffer that is actually something that we would very often so now if I do PD I can do ppl register text-to-speech server and that takes a G RPC server and a text-to-speech server which we don't really have yet but I'm going to say we're going to save it's a new server actually we can simply say it's an empty server because there's not going to be anything in there so let's define that server for now as a net destruct so so far we've created the G RPC server which is the equivalent of creating a MUX multiplexer for the HTTP package then we've said how to handle the request for text speech which is the equivalent kind of handle funk and finally we need the listener serve right and here is actually at that serve of a listener now we need to make sure that we handle that error so if error is no nil Lara's fatal F could not serve and fail there okay that is not a new variable and this one does not come Park is it says well I cannot use that server as a text-to-speech server because you're missing the same method so let's go through the recommendation find here that is the definition of the API and we're going to add that method to our server so that is context and text and this is complaining because text is not defined that is because it's PvE X and P V dot speech and our context unfortunately G RPC still does not use the near contact in the summer library so we need to replace that we've gone ended or / x / net / context cool and now this line compile but this one doesn't so let's simply say F not implement okay so now we have a G RPC server that does not do anything but we'll fix that soon but before we fix it let's call it so to call it I'm going to create a new directory now I'm going to create the client then I'm actually going to go say directly because that way we'll end up with a binary called say which is for exactly what I wanted so let's create a manor go and in this case what we need to do is rather than have port we need to know where the backend is so I'm going to call back in is a flag the string B and let's say that that d4 is localhost:8080 address of the state back end select the parse and then we're going to open a connection to that so let the dial TCP to back-end that will give as a connection in an error if the air is not nail we cannot do much so log fatal could not connect to the back end and otherwise remember to close the connection and then and now we're going to use that connection to call our server how do we do that well actually we're going to get the same line of code we have here that that imports them in we're going to add it here and TB dot new text-to-speech client receives a gr PC client connection so G OPC da new connection I think it's oh sorry now this G RPC Boudia actually G RPC dial and it looks like exactly the same except that doesn't get the TCP okay and now connection is a client connection that we can pass your ID here and that gives us that client so now we can call client dot say we need that context let's pass context of background if you don't know what context is you should check out those two episodes that I did episode 10 and 11 I want to say maybe 9 and 10 ellen:oh check it out there's like those two episodes that I did month ago or so I explained everything that you need to know about context okay so we're going to pass some text and we'll see what that text is so text it's going to be PB text where text is hello there and that will return a response on an error if the Arizona we're going to go log fatal saying could not shake this text and that will be text text and the error otherwise we want to do is we want to write a file so let's do it similar to that output is going to be flag dot string and output dot love well file where the output would be freedom and we're going to simply do I owe you - write file ah to the output and we're going to write the data which is in rest dot audio and the permission is going to be six six six that will give us an error and if that whoops any terrorism deal we will again lock fatal F could not write to the file that is the error otherwise we are done for now so now we have our G RPC server that doesn't do much and our G RPC client that doesn't matter now we want to run further server and then call the client so let's first go to the server that is totally not what I want it to go so the back end that's why and we're going to do a make bail again just in case and I'm going to run this mapping the port 8080 of my machine to the port 8080 of that container so dr. Ron - P 80 80 80 80 campoy say now that server is running we don't know it which is kind of sad so let's say Locker is info listening to port port because you know it will make it a little bit easier to see that these actually running something okay so now I run it and I'd say listening to port a ena cool so the next step that I want to do is I want to run that so I'm going to create a new one I'm going to go to the client to say go around may not go and we got L now transfer security set these may material for a different episode but I'm not using any security so I need to say that out loud in my client so we need to add that with insecure to our dial so when we do G RPC the dials are in the client so in the G opposite of dial you'll see that GOP see the dial receives also a bunch of functions in G RPC with insecurity is one of them so now if we do go wrong in the go it will not work but it will not work because if we get that error not implemented which is coming from our back-end so now we have our back in our server connecting and talking to each other yay cool so now let's make our server to actually what was one call that flight command okay so we already have this code here so I'm not going to change that much just going to try to put it there and see what happens so rather than passing this we're going to call text dot txt and we don't care about this instead we want to do is we want to get the output directly into the error so we can do combined output in the command that will give us also data so if it fails we'll do return and not speech and then error saying could actually slide fail and this is the data that we got from it otherwise these will Oh okay so where is this writing right we're going to need to create a new temporary file so I util 1010 file that will give us visible options just give me any temp file click the file if the air is o'neil then return could not create temp file and this is why we're not going to use that file at all so we can do F close directly and that returns an error in just in case I want to make sure that that works you so if we're unable to create it could not close the file and we can use F the name here and the error otherwise now we can use F don't name there so we're writing into the output file then we want to read all the contents from it so and that is the problem of comments not having an option to write into the output that you need to be forced to do this so now that we're wearing that audio into the file we're going to read it back so we're going to do i or util read file of f dot name and we're going to get data and an error if the ends are male we're going to return nil and could not read temp file and that is the error otherwise we can simply return t V dot speech where audio is set to data and nayer okay so now what we have is basically the same thing as we had before but so it's these come that's the important thing that we're doing but to make sure that we're able to get the output we need to first create a temporary file and then wait from it a little bit painful but you know it's a little bit of our work around this another option could probably be to use siegel and maybe there's a seagull library for this or maybe it's a good idea for a next episode let me know if you'd be interested in me writing a seagull wrapping for flight why not could be fun or not I'm actually not sure cool okay so now we're going to go back to our back end we're going to rebuild it we're going to run it again so dr. run cowboy say we're listening now we're going to create one more we're going to go to say go run may not go hello and that created an output dot valve actually I think that ours our oh yeah it says he'll there so we should having that up to the but that we just created should we should have hello there so let's see it is a great moment hello that is a very ugly voice but it works awesome okay let's change this so we're going to get the text from arcs and we should make sure that if OS dot arcs equals is less than 2 then we should print something saying usage - n - t this or text to speak pretty sure that's broken English but I don't care about it right now and r0 + OS exit of 1 if land of dad and they sprint F okay so let's try it again so if I do go around maybe I'll go that should say usage that's normal if I do which say these are being say and that is not to say I want to use its go path being say but yeah it's it will say the way to do scope admin say it's text to speak so that is a pump here I do hello you will refresh the output dot valve and if we play it again hello it just plays hello cool so we have a server that is running we have a client that is running we can distribute our client easily to everyone around the world but what about server where do we want to run it and what I'm going to do is I'm going to run it on kubernetes if you've never used kubernetes this is the logo and I'm going to be using it on the easiest place for me to run it which is on GK group container engine and at the container it's variable okay for two reasons one it's cooler and second it actually stands for kubernetes and GCE was taken for Google compute engine anyway so we're going to do is we're going to create a new Google cloud platform project create a kubernetes cluster on gke and deploy my server to the cluster so we can use it from anywhere in the world let's do that now so I'm going to go to console the cloud.google.com and I'm going I already have a project created just for fun prep and I'm going to go to come container engine right here and create a new cluster now when I create a new cluster I can choose the side what's the size when I where I want to have it etc we're going to have it as close as possible to here which is us west a or B that doesn't matter I'm going to say that we're going to have pretty small machines one superior machine we're going to have three of them so if one goes down not on the ways you have two more that they're working and that third one will be restarted automatically which is pretty nice and that is pretty much it so we're going to create it and well this is creating it we're going to go back here and use g-cloud we're going to use g-cloud to config we're going to configure a g-cloud to make sure that we're using the right project so in my case I'm going to do config set account can't pull your gun on the road that's what I'm using okay g-cloud config set project is going to be just for func - Bret g-cloud config set compute knock employ compute zone is going to be us West 1a and region it's going to be us one so now if I do g-cloud container clusters list you should be able to see one platter there you go and it's provisioning now it's being created so it's not ready yet to use it but it will really bread in a minute and this will allow us to use kubernetes directly there so that's pretty simple cool so now to use kubernetes we need to understand how that is work so we're going to be using two different concepts mainly a little bit more than that actually but we're going to have come to deployments and services and a deployment is basically how we're going to run our servers right so basically we're going to say what is the image of our container image right where to find it we'll see how to publish it without really publishing it to the world I don't want to push it to docker hub is there a better way to do it and yes there is but we're going to say run that image and how many times I'm going to say I want to run it three times right and then if for any reason one of them just dies or the server crashes or whatever it will be restarted automatically by kubernetes which is very nice that's the whole point now that is a deployment on the other side we will have a service and a service is not how to run it but how to access those things that are running it so we're going to have a service a service exposing act balance or API that will actually be a load balancer removal cloud platform and that will give us a an exposed API that we can call from our client and every single time that we call it will go to one of the backends that are actually running this this docker container let's write the file that explained this in code so what I'm going to do is I'm going to add in the backend one more file then gonna call cubanelles da-jung and in there I'm going to have two things and since I have the worst memory I'm going to go to the commentation and search for kubernetes deployment and criminality Flyman let's see here that is what we want to do so that is a deployment and there's a couple of mistakes in this and actually send a pull request but this should be extension not ABS I don't know how that ended up there and then these are going to be an NG next deployment there's going to be a save eternal the apps going to be say say and the image that is the interesting part because how like what is the image I could say can police say which is what I've used so far but then I need to push it push it to docker hub and you know that requires open sourcing at least for me so rather than doing that I'm going to use Google container registry which is a registry that belongs in your project so only you or people that you share the project with can access it which is very nice so what I'm going to do is I'm going to change my make file to say that the name of this is now GCR the Rio that Google container registry then the project ID just for fun - prep in the name of the image that you want slash say and then I'm going to add one more which is push and that will do is docker push of this since we need to send it to DC at i/o we're actually going to say g-cloud docker - - bush and these will basically do with docker push but we'll handle all the authentication to access CCR correctly by simply having that jiggler there cool so now I could do make bill and make push and now while this is pushing we can get this and use it on my image the container for done I'm going to be using is a da okay so now let's see if this is ready okay so the other cluster is running so now I can do cute CTL actually before I do that I need to do G cloud container cluster get credentials of the name of the cluster which I already forgot but we named that cluster cluster one that's not the most beautiful link but we don't care cluster one and now we fetch the configuration so now choose CTL when we do get notes for instance they will show us the three instances that we're running in the cluster so I can do cube CTL and actually I use an alias okay stands for cube CTL so if you seek a get notes that's exactly the same so I'm going to do cube CTL or cube cuttle depending who you are and then going to do create the file here so now we created the planet by simply running this we can see the pods and we have three plots running this this image and they're already running that was really fast so now we want to do is we actually want to expose this to the world to do that what we need is a service so let's go to the commentation cuban any service and the kubernetes service I'm going to copy paste because that's you know this way and I'm going to add it in the same file but with three dashes and when you have three dashes and gamma means that that is an X and a new file so you should treat it as such so I'm going to add this of it's a new service I'm going to call it say service the selector it's application say it's the one that allows you to find that it's these templates everything query with this template those parts in a part is basically a container it's a group of containers that are grouped together but in our case we only have one so you can imagine that there's just one container so all of those containers are tagged with the label application say and that's how we target how we map from service to the pots we're going to exposing port 8080 and the target port is going to be the same so we don't need to expose it and finally we need to say type load balancer and with the type load balancer what we're saying is we want this to be exposed to the world and we want a public API okay so let's try to run create again one of them will fail because it says these already exist but it's fine but I already create the service so now I can go get the services and there's an external API that is pending so I can do dash W and this will watch the API it will actually do a long pole and wait until we get an e we have IP and show it directly here once we have that IP I should be able to run my client with that IP and everything should work we will see and while this is running I need to think about what do I want to say okay so I think I know what I'm say oh say so let's go run man go go - be victory and yes play I put three really three hmm I need something wrong and pretty sure oh that's so wrong okay because that is now how you get parameters when you have also flags that is actually flag the that's so silly flag dot and argh that's the number of arguments is less than 1 then we fail otherwise we're going to pass here flag dot R zero basically the same but otherwise we're saying be because there's - be and that - be the flag is actually consider the first argument so that's why this is happening so that was wrong code and now it's better I hope so let's just run it again and I'm gonna run it victory because I'm very confident on this victory victory awesome that's it sounds like curry that's a very good action and I'm saying that so this is the end of the episode I hope you liked it there was a lot of things that I went really fast on G a B C and kubernetes and how to define protocol buffers and cetera so I will have a bunch of links on the video description so you can learn more about it I definitely recommend reading some of those Doc's there's a lot to learn this was just a concrete use case of those technologies I hope you enjoyed it and you've got most of it as always feel free to send me your questions your feedback probably the two easiest ways are I'm front desk on Twitter or you can also just comment down here on the videos on the on the comments section of YouTube which is you know it's actually surprisingly nice for my video so thank you so much for being so gorgeous and always I will open source this very soon sorry for being one day late again as always really I was late because I had a good reason I was presenting at gopher Fest yesterday and it was livestream so we'll also have a link to that last ring if you want to see what it's coming up with go under 9 also a rock I give a really cool talk on his new project the project where she's working now I call up spin so you can check that out too I will open source all of the code soon so hopefully you should be able to say that github calm slash Campo is flashed just for funk as always please subscribe and thanks for watching [Music]
Info
Channel: justforfunc: Programming in Go
Views: 31,579
Rating: undefined out of 5
Keywords: golang, grpc, kubernetes, google cloud, google cloud platform, google container engine
Id: XaMr--wAuSI
Channel Id: undefined
Length: 47min 28sec (2848 seconds)
Published: Wed May 17 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.