st you money the virtual machine but also the public ip address if it's not in use there's a very small fee to pay every month if it is in use you don't have to pay but if it's not in use you will have to pay for it so make sure that those are for sure deleted the network security group you don't incur any charges for that and the virtual network neither but to make everything clean you could actually remove this whole resource group if you're done testing i will just remove this whole resource group so that's it for this lecture that was quite a lot to get this vm launched but at least you got some training in launching all these different resources so now if you want to launch another resource like a database just have a look at the reference documentation at the sdk and it should be fairly straightforward very similar to what we did to launch other resources on azure in the next coming lectures i'm going to show you how to use go with kubernetes if you're not familiar with kubernetes yet i would recommend you to first take a kubernetes course i have another kubernetes course on udemy for example that you can take what are we going to do in this first lecture is i'm going to show you how to use the kubernetes client in go kubernetes has an api it's a well-documented api that you can call using rest calls so just over htp using x519 certificates for authentication so we have certificates configured in our kube config configuration file and using those certificates you can authenticate to this htp rust api the kubernetes api and interact with it you could do this with curl you could do this with the htp client in go but it would be again very evolved to do this all yourself so there is a kubernetes go client available that will do all the heavy lifting for us and we just have to supply the config file and the api calls that you want to make the kubernetes api will then reply with a json response when we do api calls we do an api call and the kubernetes api response with json this kubernetes api is the same for any kubernetes distribution whether you run minicube or on alos using cops or the google kubernetes engine or the azure kubernetes engine or anything else it should always be the same there are differences but mainly in the api version of the kubernetes api so depending on what kubernetes version you're running you will need a different go client the version does need to exactly match but on their github page they have a matrix to see what client version is compatible with what server version to make these demos work you need a kubernetes cluster the easiest way to have a kubernetes cluster running on your machine is using minicube so let's have a look at minicube this is the kubernetes minicube github page so it's github.com kubernetes minicube and here you can download minicube either from the release or you could actually go to the documentation there is the documentation here that has an installation page to get started page and here it explains what you need all you need is docker or similarly compatible or a virtual machine environment what does that mean you need either docker installed like just docker for windows docker for mac or you need virtualization support hyperkit hyper v parallels virtual boxes are free that you can download if you don't have docker installed or it's not compatible with your system then your operating system i'm on macOS but if you are windows then you just a few commands that you have to enter to download the installer and to add it to your path if you are windows i also like this one chocolatey it's a package manager you can just install the package manager and then do choco install minicube and then you'll do everything for you i'm on macOS i will execute these commands or you can use brew as well and then you can start a cluster with minicube start if you have any problem with minicube start it'll most likely be that you have an issue with any of these virtualization machine managers so for example if you run the virtual box there's a virtual box page that can have a look how to use virtual box in case of virtual box you first need to download it and then minicube start driver virtual box to run minicube on virtual box the easiest way i find is use docker i have docker installed so minicube will run within a docker container on my laptop so when i'm going to do the demo in the next course i will have my minicube cluster running and the only thing that i did is just minicube start in this demo i will try to deploy a new container packaged in a deployment on our kubernetes cluster that is running locally so i started in a new directory kubernetes demo i did the go mod in it i have a main function and the first thing i need to do is i need to read about how the go client for kubernetes works so let's go to github invite app kubernetes go client in google then github.com kubernetes client go this is it and here it says what i need to do first it says have a look at the compatibility matrix depending on what version you are using what kubernetes version you are using you want a different kubernetes go client and how to get it go get client go together with the version number so also they say we recommend using the v0 x y tax for kubernetes releases 1170 so i am on 124 so i should use v0 24 and then the minor version so i'm on 20 so i'm going to use the 024 1 so go get kubernetes client this is what i copied from the main page 20.4 so i am on 24.1 so you can know that by doing kubectl version or just have a look at your output of minikubes started to also tell you what kubernetes version you are on other versions will also work so if you have a newer version it most likely will also work it just for best compatibility you should use one that matches it's just that there are new api calls introduced in later versions so if you want to use those new api calls then you need to use the correct version for the api calls that we are going to use you could even use an older version so you could even potentially use this version it just depends whether these api calls of this deployment are going to change if they change you will need a new version for a newer kubernetes cluster and when we do this go get we get an error so it has it requires this google cloud google.com this package and this package and when it arrives at github.com go lang mock 143 then it says cannot authenticate record data in server response it's possible that when you do go get a newer version that you don't get an error it just there is something wrong currently in this mock repository for some reason i cannot get a 143 version but then when i tried earlier i can get a 144 version so this is an excellent opportunity to show you how to force a certain version so we can say replace and then this package without a version so when we see github.com go lang mock replace it in still the same still the same package we could also change another package for example if you would fork it on your own repository make a fix you could also do a replace and then this would be instead of go lang it would be your github account but we are going to keep it we're going to keep it on this go lang mock we're just going to force it to a different version so we're going to say i want to use the 144 instead of 143 and it actually works so now we are using the v0241 kubernetes client and we're forcing it to use the mock version from 144 so just like our other packages we first need to initialize it we need to make sure that we provide the correct config so let's have another look at this client go they have an example somewhere how to use it if your application runs in a pod in the cluster please refer to our in cluster example otherwise please refer to the out of cluster example so there are two ways of authenticating in kubernetes if you're within the cluster it's easier because then the api server is already there you just have to contact it locally and it knows that you are coming from within a pod but if you're externally then you need to do authentication you need your certificates so it needs a cube config file so let's have a look at this example main go and then here we have some code that we can use create the client set so this client that we need and with this client that we can then do api calls so we can do core v1 pods list the pods of my kubernetes cluster or create a deployment so i'm going to copy this client set because this is how we're going to get our kubernetes config actually i'm also going to copy this let me just copy everything i will remove these flag parts because we are not going to work with flags it's always good to start from an example so we are going to call this our get client function and we are going to return we are going to return whatever this new for config is going to return we don't know yet because we need to save it and import some variables so let me just put this first all in the function so this is just the code that we copy pasted and i'm not going to work with this flag so i'm going to remove this first and what i'm i'm going to do i'm not going to check whether a home directory was supplied i'm going to straight to this home directory and that's going to be my path where i'm going to look for this cube config file so if you want to supply another cube config you can just hard-code it here because build config from flags the second parameter here is just a path to your config file the path to your config file should be your home directory so this till design is my home directory and cube config is then your kubernetes configuration on windows it should also be in home directory in the cube directory and you should have the config file if your config file is somewhere else then you could override it you could just say my cube config is for example just a file called config in the directory where i am executing this gallant program so let's save this it's not automatically adding all these things these imports so i will have to end them myself or i can copy paste them from the example let's just copy paste everything that i found here save this it'll remove the ones that i'm not using and we might have to import some more let me try to see if i need to import this go get this kubernetes this is already imported go because this is also already imported yeah because i did import of this and it also has all the sub directories okay so now that i did this go get visual studio actually updated this go mod file so now i have the correct packages in my go mod file what do i get here i get a kubernetes client set so what i'm going to return is this kubernetes client set and potentially an error and then i can say again var client is my kubernetes client set and i'm going to do if uh client an error but then i will have to define the error as well this is the error get the client if error is not equal to nil then i'm going to print the error and i'm going to always exit one save this okay i need to remove this colon client is not used and here i still need to return either an error or nil and the client set client set nil because nil the error is nil client is here and i could already test this so printf tests i have no idea what is in this client it just functions that we can use so i just try to print it which will give us some useless information i guess but i want to see if this actually works i want to clear go run dot go what does it do no corporation has been provided try to think kubernetes master environment variable so it's actually not working as because my kubernetes cluster is not running so if i do kubectl get pots it says localhost refused so i need to still run my minikube cluster and it's going to say that it detected the docker driver and now it's going to create this docker driver so now it needs to run this kubernetes cluster so i'm sorry about the noise it's going to make the background noise because this is all very heavy and then my macbook starts using its finance well so actually i'm not on 124 i'm on 123 but 124 will will come out very early i think i just have an older minikube version right now installed and 124 will be out very soon and this 124 this 024 that i'm running here will work with the v23 as well let's try to run our program again okay so now i have the client ready so now we can do the actual deploy code and i'll just pass for a second because this fan noise will stop once everything is booted up now that we have the client we can actually connect to our kubernetes cluster so let's try to run a deployment i have here an apple demo file of type deployment this is the api version it has a name hello all deployment and specification we are going to run one replica so one instance of our deployment and then we have a selector which is going to select the template with the app hello label so we have here the template and the specification of our container so this specification will run the kubernetes demo from my docker hub repository and it will expose a port port 3000 so this runs on port 3000 so with this label we will also see in the pot definition so later on we can filter on the pots that have this label to see whether our pot is running what do we need to do first we need to do the deployment so let's create a function deploy and what are we going to return we'll see that later we'll start with an error and then we can we need to pass the client for sure so we need to have the client kubernetes client set and then here let's start with an error deploy and we're gonna pass this client so and this we can remove or we can say just deploy it deploy finished just so that we have something that we know that the deploy has finished so how how do we do this api call well the api version is apps v1 so you will find this also in this client you see apps v1 is an endpoint on this rest api so you will see within this client package we also have this division the same as the api endpoints so apps v1 deployments and here we have to pass something namespace which is a string so either we can say empty which is going to then use the default namespace or we can specify the default namespace or we can create a namespace so i'm going to say default or you could pass this parameter or you could just hard code it where if you want to deploy to another one then default so default is the one that is there by default in minicube and we can then do apply create the lead get list patch update let's start with create because that's the easiest one create and we need to pass a context so let me pass again a context here and then i will have a new context here context background and i will pass it as well context so we have a context and then we have a deployment v1 deployment so this v1 deployment is actually all this but it needs to be in this v1 deployment type and it's still in yaml so we need to pass this and actually these these Kubernetes packages they have something to pass it so let's let's not let's not do it like that let's pass deployment and then we're going to say par deployment is a new pointer to v1 deployment then we need to add another argument are create options create options which doesn't seem to work because what is v1 here apps v1 let's have a look in this create definition meta v1 okay so we can just copy paste meta v1 so these are the create options that we can pass meta v1 oh meta v1 and then here this also is called meta v1 and it doesn't work meta v1 create options works but it's not a pointer so meta v1 this is how we should do it what does it return a deployment called deployment response the error and then if the error is not nil we can return the error deployment error like this once we have deployment response what we actually want is we want to return these labels we're going to assume that whenever we do a deploy we're going to have these labels and in the next function we want to filter on these labels when we get the pots just to see if the pots are running so if you do if you reply from this template to the labels then we can later on use them so if i say deployment response and then we have what we have here the specification and we have this here as well specification then we should have a template and then we have labels and then we have no error but we need to change our function signature because now we are returning a map this will be a map app it will be the key and hello world value and we just need to make sure that we also returns something here so the map will be nil but we still have an empty deployment object we cannot deploy an empty deployment object because it will not work it will give us an error we still need to convert this yaml file into this deployment struct and now you could use some yaml unmartial package to marshal this into this specification i actually tried it and that doesn't work 100% and when i was looking into the documentation i found that this go Kubernetes client has its own functions to do the unmartialing so some kind of helper functions that can help you it's not very well documented at this point in time so i just found it in a github issue and i'm just going to copy paste the code that i found in this github issue and then i will try to explain it so these are the two lines scheme codex universal dclizer so they call it dclizing your yaml into the Kubernetes scheme and this is the decode function that we are then going to call and the only thing that we need to supply into this decode function is the contents of our apple yaml and it will magically make a Kubernetes object from it so that's all good but i already saved it and it couldn't find this scheme so we'll need to help Visual Studio code a little bit and it's going to be in this Kubernetes package in this client Kubernetes package for a go and it's scheme and now it found it so app file is then byte so this is actually a function so we could actually make this a bit shorter because we're only going to use it once so we could also just say scheme codex universal serialize a decode and this is our function our decode function decode attempts to desalize the provider data which is yaml but i think it can also be something else you can probably be also json that's why it's really a decoder and not just un-mushler because it just accepts bytes and yaml and json are compatible so it says the object is not guaranteed to be populated we need to still this runtime object we still need to figure out whether it's a deployment object let's start with reading our file so app file error equals io read file it's io util read file and read file expects a file name our file name is applet yaml read file error in case there's an error so you read the applet yaml file pass it here to the decode function and the decode function gives us a runtime object this object is going to be of type v1 deployment but we don't know yet because this is a universal function for all the Kubernetes objects it just gives us a runtime object and we need to test whether this could be of type v1 deployment and if it is of type v1 deployment we want to put it in this deployment variable and then do this create so how do we do that we can use switch object type and if the type is v1 deployment then we can say case v1 deployment then we know it's this type but if it is not this type then we can make a catchall default so then we can say return an error unrecognized type and the type is of group version kind so it also returns the type this universal serializer so if we don't know then we can give a clue and then we might have to add more cases so v1 deployment if it's v1 deployment then deployment equals the object but with the v1 deployment type so we're just going to change this object type to v1 deployment save this and then we could actually test it so let's try to test it let's have a look whether we have deployments qtl get deployments no we don't have any deployments we don't have any pots okay let's run this deploy oops i still have an error somewhere oh yeah i didn't change this code here so we will say deployment labels is a map string string and then deployment labels deploy finished did a deploy with labels i never thought i could output it deploy labels all right let's try again let's check our deployment qtl get deployments and we have the hello world deployment and we have the pot running let's try to do another go run and this is a bit annoying you can only run it once because it already exists so let's try to change our code a little bit so that we we can make change to our app yaml and then it will still apply the changes what i want to do now is i want to check whether the deployment already exists if not i want to create it if it exists i want to update it so instead of create we can also do a get i'm going to do a get context then the name of the deployment and then the get options so context the name deployment name we should then be hello world deployment and then the meta v1 get options what is returned a deployment but i actually only want to know whether it exists or not and if it doesn't exist it will throw an error so i will just check if there's an error if error is not equals to nil and i want to split it out i want to say if there is an error and it is not found then i will do something if there's another error i will not return an error and there is a package within the kubernetes client that we can use for that there's an errors package that can check whether something is not found so i'm going to add the kubernetes io api machinery and the errors package and you might have to do a go get of this package if you don't have it yet what you can then do is if error is not nil and errors is not found over the error so if this error includes is not found it's not found returns true if the specified error was created by a new not found so if this deployment get returns is not found then we go in this conditional else if error is not nil and the errors is not found but we are going to reverse this so if it's not is not found then it's a real error let me say deployment get error and otherwise if it's not found then we just move this code in here because if it's not found then we need to create it if it is found then we're going to update it and then we need to have the update options that way we can override our deployment just like that if it is already created so there's a deployment so let's test this no deployment deploy finished the deploy with labels map hello world one replica let's now put three replicas and then instead of an error we should get the deploy is finished the deploy and now you have three replicas and three pots running so and if you put it back to one then it should still work so this now will do the update if it already exists and create if it doesn't exist now next what we can also do is we can have another function to wait for the pots whether they are running or not here they are quickly running because we already have downloaded the image and there's no health checks on it but other pots it can take a couple of minutes before they are in the running state so we want to check on that now that we have our deploy running let's have a look at how we can wait after our deploy so we do our deploy but ideally we want to make sure that all the pots are running because the deploy only creates a deploy object a deploy resource in Kubernetes it doesn't mean that our pots are already running so ideally and that's why we are getting these deployment labels these deployment labels are going to be pushed to our pots so our pots will also have the labels app and hello world so we can filter on those as long as those are unique to see whether our pots are running so i'm going to make another function deploy client and i'm also going to pass deployment labels which is a map string string so it's going to be the key is going to be the app and the value the hello world wait for pots i'm going to call it and i'm just going to copy this this is going to be called wait for pots and we're going to return an error in case something goes wrong and we're going to pass these these labels which is a map string string and at the end we're going to return l what are we going to do we are going to block our goal line program with a indefinite loop and to make an indefinite loop you just write four colored brackets and then we will stay forever in this for a loop until we hit the break point once we hit break then the loop is over in this loop we are going to list the pots and only when they are all running we're going to break and otherwise we're just going to keep our program running or we could say also that we are only running it for 10 checks so after 10 times we checked whether the pots are running we abort or we could just keep it running and you can abort with control c so we are going to use client client apps v1 again oh it's not going to be apps v1 because it's not going to be a deployment or a demon set or replica set it's going to be a pot and a pot is in a different function it in let's have a look what do we have core v1 so you see you have autoscaling batch certificates there's a lot of api endpoints that you see here that are typical in Kubernetes core v1 contains the pots near core v1 and then pots pots accept a namespace namespace can be default you can make a static variable of this or you could even pass it as a parameter instead of repeating it and what are we going to do we're going to list the pots list accept the context and meta v1 list options and it returns a pot list an error pot list error if there is an error then pot list error and now we can iterate over the pots so we are looking for pots not running so pots not running is zero then we're going to do a for loop for key value range pot list pot list is not an array it's a struct pot list items is an array so we're gonna iterate over that and then we get a pot we don't need the key so we use underscore which means that we don't need this variable and it's a pot then we can say if pot what do we have here pot status and what is status pot status pot status phase is not equal to running so it's not equal to running then we say pots not running plus plus so plus one and then if our pots not running is zero then we can do the break pots not running let's make this pots running actually and then if it's equal to pot running then we're going to increment this because we need at least one running otherwise otherwise we're just going to exit so if pots running and then i will have also all pots or i can use the length of the items pots running if pot running is greater than zero then we have pots running but pot running also needs to be equal to the length of the pot list item so because all our pots need to be running and then we can break what is not happening still is that we are not passing our labels so let's also pass our labels and we can pass our labels in the list options we have a label selector selector to restrict the list of returned objects by their labels defaults to everything say label selector and going to be a string and we can again use some helper functions if you want so we already use this errors errors helper functions of the api machinery and we have some more helper functions in there we have the labels and we just need to remove this api because it's not an api it's just pkg labels and if we then have look at labels and just comment this out labels when that doesn't seem to work labels i'm just gonna save no sometimes it's a bit difficult if you haven't imported a package yet to get the visual studio code to autocomplete so this is clearly labels but it doesn't want autocomplete labels so if i command click on this then i get the api machinery labels documentation and then i can also have look here so there is a validate selector from set then i'm going to use validated selector from set returns a selector labels validate oh and now i see what is going wrong so if you use your labels as a map string string you cannot use labels from the import so i'm just need i just need to rename this one labels deployment labels and now i will be able to use labels from my import validate and then i can pass a labels set and this label set is a map string string so i can just pass this deployment labels in this validated selector from set and it will reply a selector i'll say pass labels or validated labels error so if my labels are invalid it will also return error so it's a very nice helper function just to make sure that your labels are correct and this then has a function to pass to a label selector just a string function and then it will be 100 correct what we pass to our list options so now we do the wait for pods we have a for loop i'm just a little bit scared that we are going to breaking out of the for loop too quickly because not all pods might be created at the same time so what we could do is we could also reply the replication amount so if we say deployment response spec replicas then we could use also the amount of replicas that we expect in our wait for pods function just to be 100% sure for our simple use case i don't think we need it we could also just do a time sleep here which is not very nice but we could also just wait a little bit before we are going to check whether this deployment is created in general when we are using mini cube the pods are pretty quickly created so for our use case it shouldn't really be a problem but if you want to be sure and you want to check off all the edge cases you will need to also make sure that the pods that are running is equals to the replication factor so if we are checking we can say waiting for pods to become ready running D out of D and we can say pods running that's the ones that we found and the total is the pot the length of the pod list items and like just n and then we go to a time sleep five seconds and then we will just sleep five seconds and then go again in this indefinite loop until we break the loop i think that's it i would like to test this let's already spin up our mini cube cluster and we just go over the code one more time so we have the pods running zero we do pods running plus plus if the face is running only if the pods running is greater than zero and it's equal to the total of the positive that are being returned then we're gonna break sounds okay let's test this go run go uh-huh waiting for pods to become ready so you see so that's why we need this zero because when we check the first time there's no pods and if you wouldn't check for this greater than zero it will already have kicked us out okay deploy finished did it deploy with labels map hello world so we could actually put this fmt higher so that it's also outputting one out of one so we do a cube ctl get pods we have one let's try to do this with three not sure if this is still going to work because when we change it it's already it's already going to see it's already going to have a pod running so that's why we need this deployment response spec replicas so that we can pause it as well expected pods is an int was a replicas an int int 32 we'll dereference it and then int I'll just need to add change all returns add zero everywhere I'll make it in 32 and make it here also in 32 still have an error that's it and then we can add expected pods and we can pause it here and then we add a parameter and we just need to compare and pods running equals to expected pods okay and also because pods running as int we need to change the type from int 32 int we could have also done that earlier and we didn't have to pause in 32 we could have done that here as well could have done that right here as well if you want it okay let's try this so let's now start five pods waiting for pods to become ready uh-huh and now it works yeah first we have three out of three and now we have five out of five so this is how we can also have a function to wait for the pods and then we can have another function after wait for pods where we do something with those pods maybe we want to update another system or you want to execute something in them or you want to verify something it's always good to have a function to wait for a certain state and this is where we wait for a certain state and this is typically implemented with a for loop that is going to be running forever until we break the for loop so that's it for this demo we have created our first goal line program that can interact with our kubernetes cluster and the other api calls are very very similar so once you know how to work with pods you can use this client set to interact with all the other apis as well in this demo i'm going to rework the kubernetes demo the deploy that we did in the previous demo and i want instead of to supply this this ability ammo i want to have this ability on my github i will never make a change in my github repository i want to have it updated on my kubernetes cluster so i'm going to create a new github repository add a webhook and when this webhook is invoked i want to have it deploy on the kubernetes cluster so what do i need to do for that let's have a look i first don't need these so i can remove those and then the cat client i'm going to change a little bit because i want to eventually run this in my cluster so i'm going to say in cluster bool and then if in cluster then we are going to do something else then uh then not in cluster so the config is going to be different if he are in the cluster because then we have rust in cluster config and this returns also rust config just like this one so i'm going to move this in my if right here i'm going to declare the variables error and config right here and this also accepts an error so now we have the cat client that is going to create a client set depending whether we're going to pass in cluster or not we are first going to say false because i want to test it first outside the cluster then when it works i want to move it in the cluster so we might not need everything here anymore let me clean this up a little bit and what we are going to do is we're going to create a server an htp server that is going to be able to receive our webhooks from github so github every time there's a push is going to send us a webhook so we need to be able to capture those webhooks github is just going to send us a post request we just need to capture the post requests htp listen and listen and serve this is how you can listen on a port in go the address can just be 8080 so that it listens on port 8080 and we don't need a handler we don't need this handler we are just going to define one htp handler here we are going to say that if we hit webhook then we are going to invoke an htp function so we need to write our server and our server will have an htp function so let's create a file server.go it's still going to be package main but you could perhaps move this to a separate package if you later want to make it a bigger program then we're going to have a function our webhook and i'm just going to copy this function signature from here so handle func accept a function this is the function i'm going to write and there's going to be our requests and our writer so that's htp and then we're going to write a struct that's going to keep all the information that we need type let's call it server struct and what information are we going to keep this client that's the first thing we are going to keep and now we can define it as is a new server and our client is the client and then we can pass the function but if you're going to pass this function webhook this is going to work it's going to compile but this webhook doesn't have access to our client so if you make this function part of our struct then we will be able to reach a client using s.client going to save this and then we just need to do s.webhook because now the webhook is within the struct going to save this and fmt print f test just to see if it works will it work uh no it doesn't work because my Kubernetes cluster is not running let's maybe just comment this and this and let's try again okay seems to be working curl localhost 8080 page not found okay and now bit webhook it output test so this is working all good so far we can uncomment this our server is working what do we need to do when we hit this webhook we need to do the deploy on the Kubernetes cluster where do we get this deployment file from this app.yml from git so the webhook will supply us some information some information in the json from the push notification and we can analyze that there is a github sdk for goline so let's have a look at that github goline sdk i type this in google and then we have the go github so we can do go get github.com google slash go github v45 and then how do how does it work you can construct a new client we can do authentication so we can pass our access token in case our repository is private then we can supply this access token and then we can use this client and this client has several ways of then querying the github api and it's all described in the godok reference so for example we want to download a file from our github repository so if i just look for download here download artifact download contents artifact is probably something else download contents is download a file and we can pass an owner a repo file path so we can try to download our file using this function from the repository's service in this github sdk so github will send us a push you just have to analyze this push it's a json in this push request it will tell us what files are updated and added and then for every file that is updated and added we can invoke this download contents and then we just need to do the deploy on Kubernetes to send the YAML definition that we basically put on our github repository so this webhook let's have a look how this works there's a webhook section here go github provides structs for almost all github webhook events how do they look like we need a push request so if i look in the list there's a push and there's an example payload so we already see here commits an area of commit objects describing the pushed commits and here's an example so this is how it looks like we will extract from the repository the name and we have the full name and we have repository owner the name so we could use name plus repository name for example and then we just have to extract the files that are added send it to our Kubernetes server this is the event and we can parse this event using this github SDK so we don't need the structs ourselves we don't need to create these structs to translate JSON into a goal line this is all done for us so we could basically copy this code and make an event for a github push and extract the parts that we need so let's try that out let's first initialize the client and we are going to support authentication so let's copy this so we could create another github.go we could just do it here we have the get client and we do get github client what will it return we don't know yet it's going to return this new client from github so let's make sure that we do a go get go get off this github we added this let's add this here go github we call this github and github new client let's save this or in order to look at it there's a slash github that we need to add it's going to be like this package github and then new client it gives us a github client so we can do a return of the github client and we can pass access token and what if we don't have an access token what if the github repository is public then we pass nil so we can actually say if access token is empty then we are just going to return a client with no authentication and otherwise we're gonna add the contacts here and otherwise then we are going to use a static token access token and the new client so it uses this OAuth2 package to make sure that every time we do a get or post request that this includes this token so there's almost nothing we have to do ourselves we just have to glue all this code together get github client returns a new github client we need to store that again we can say github client and then in here we can say get hit up get github client also context context is new context and the second parameter is our token i will just read the token from our environment github token does it all work what does it reply string what does this reply the github client is there no error okay there cannot be any error so we don't need this error then we have github client and then we're going to use github client is github client we need to add it here as well github client is a github client and actually maybe we don't even need this intermediate variables we could also remove this say s is a new server and then still do s.client and s.github client and this is the same and then we need a little bit less of code which is always beneficial okay so far so good github github client i'm going to save this this is going to be imported still an error here i'm not sure why probably i have to okay i needed another go get and then maybe my gomot was not updated or something like that so what do we need to do now let's have a look at this webhook code can just copy paste this to start with what is our payload validate payload and then we can just pass the request htp request so if you pass the request then it will extract the payload itself so this json it knows how to extract it as long as we pass this request and then we have the webhook at secret key so we need to have a webhook secret key which is going to be of type string and we also need to get this from somewhere so i'm also going to provide this webhook secret as an environment variable or as get nth webhook secret and this is a secret that we can define when we create the webhook just as a validation whether it's our own webhook or it's someone else's webhook making these requests so that if you don't have the secret that you cannot impersonate that you are a github if error is not equal to nil then what should we do then we should probably send an error 500 back to the client we can do that by doing right header header write header write 500 which is which it gives us a 500 error but then we also would like to print the error on our screen or in our logs eventually and then we say validate payload error and the error and then we return so we stop the function so we could put these three lines in a function and call this function or we are just going to be a little bit lazy and go we paste it first is a validate payload then we're going to parse the payload and then if it's parsed it's going to be in event and that event we can again check to see what type of event it is and these are types in go from this SDK and we should have a push event type and this is the event type that we are going to use we probably want the default as well to just say that we don't have this kind of event event not found event not found and then the event type what is this 500 or i'm probably using the wrong function all right what is this htp request oh i see what i did this is the response writer and this is the request and this webhook secret key should be a bind bind and then this writer is going to be write header 500 so now write the header which is off-code 500 and that should all work we save it oh it's also going to be request save it looks like it all works so the webhook comes in we validate it we parse the webhook and then what do we do with it so now that we have access to this push event we could extract some information and mainly we're going to have to extract the files so this is going to contain the commits so let me write a function for that i'm going to pass this commits to a function files is get files commits and then i will write this separately because this is going to take some space get files commit and commit is off-head commit commits is off the github had commits get files what do we return a string slides we will need to loop over these commits this is one commit arrange commits so let's loop over this and then let's have a look in this commit what is in this commit we have removed we have added and we also have modified so let's say that we have all files is a string slides now we want to append to it but this edit is also a slice so we basically want to merge two slides which we can also do it up and we just need to add three dots after our slice and then these two slices will be merged and we will be put in all files we can do the same for the modified files but what if a file then is duplicated let's try to remove all the duplicates as well how to do that easily we can put all the files in a map and then put the map back into a slice so we're going to have all unique files is a map string bool and then we're going to go iterate over these all files file file name range all files and then what we are just going to say all unique files is file name and it's true all unique files file name true and we still need to convert it back into a slice so now we can say for file name range all unique files and then we can say all unique files slice is another slice i'm probably doing it in too many steps because i could have put it in i could have put it in a map already here but yeah now i've already started what are we going to do then append this file name here and i'm going to return all unique files slice when i write something like this i always want to test it so let's write a server test go and quickly write us a test test get files t test a t and how do we test this we get the files files equals get files and then we have to supply github head commit save it first so the github is important and the head commit is an array so we need an extra set of curly brackets and then we added a file added string test dot txt and then we have no modified files if files if lem files is not equals to one then we're gonna say log fatal f no not log t fatal f expected this one needs to be modified expected only one file and i have more than one file let's try to test this files declared but not used oh it will be here files declared not used and then commit is not found because it needs to be event commits and let's just print this out found files s and i'm gonna join them together files and a comma okay that should work run test what does this do okay it passes and then back to the server now we have the files what do we need to do now now we need to download the contents for every file from github so another loop file name range files and then we have this github client repositories and what was it something with download download contents and download contents gives us a read closer the response and error downloaded file i don't think we need a response and the error if the error is not nil then again we will do this download contents error what goes in it the context we have context no we don't have a context we only need one so i will say context background context background and then oh my macbook seems to not be able to follow for a second it's because i'm making a bit messy here context owner repo file path and options contents and what was it repo repo is i can find this in this event event repo and then first i need the owner name this is going to be the github username and event repo name and then the file path is file name and then github repository contents cat options which is probably going to be empty and then i think that these are pointer strings so i want to make sure that we pass them we pass the actual values to them save this and now i have this downloaded file it's of i will read closer so i need to make sure that i also close it close but we differ and then we can download it just like we did with our htp streams we can say i will read all downloaded file and this is the body file body error again error handling read all now that we have the file body we can do the deploy deploy we need a context so let me just use the same context again context is context background and context background and then pass the context here the client we could also move this deploy into this server struct and then we wouldn't have to supply the client but it doesn't really matter here and then we get back the map the pots and whether there was an error i don't think we need those first two but we need to pass this file body somehow so i'm gonna pass this file body which is of binds and i'm going to add a parameter app file and i don't need to read app file because this also reads everything in binds going to save this this works this works save this deploy error so what else do we need so we are first going to test this outside our cluster and it's going to then do what start a server start a server here it will initialize my github client and my get client it will then wait for the webhook if there's a webhook it will validate it parse it will get some information out of it like the owner of the repo the name of the repo the files and then for every unique file we have we'll do a deploy and then we can just say deploy of file name finished and then file name is the file name is the file name all right so let's try to get this operational we need a webhook secret we're gonna enter the environment variables here if you are on windows i think what is easiest is to add a configuration go launch package and then you have the nf here nf that you can use so here you can then say webhook secret and so on and then you do run run without debugging and then the environment variables are injected i'm not going to do that i'm just gonna put them on screen here webhook secret my secret i can choose it myself so i'm just gonna keep it simple and the github token so we still need to create a github token so let me create a github token for my own github account so this is my account and on the right top i'll go to settings and then there's developer settings here left bottom and then i'm going to create a new personal access token you can click generate new token you will have to enter your password we are doing a go demo only to be valid for seven days and then we will need to have repo control that should allow us to access the repositories and then download the data generate token this is a token i'll copy it and then i can enter it here the github token and i'm going to do go run dot go which will not work unless i'm going to start my mini cube cluster but how can github access my server if it's running on my computer well either you have a public ip address which i don't have because this is just a residential connection i mean i have a public ip address but this port 88 is not going to be accessible on this public ip address another i'm going to do some complicated port forwarding so the easiest way to have the forwarding setup is to use something called ngrok it's another piece of software that you can download so if you go to ngrok.com serve web apps with one command sign up for free so this you can download brew install ngrok or with windows zip file or you can install first chocolate the package manager and then install ngrok or there's also a docker so it's the fastest way to put anything on the internet so you install this and then when you have it installed you will have to run ngrok so i already have it set up so i'm just going to type ngrok and then it will give me the help ngrok so ngrok will tunnel local ports to public URLs so if i do ngrok hsp 80 it will make 80 public but i'm going to write on 8080 so i will do ngrok hsp 8080 ngrok so i'm online my session will expire in two hours there's terms of service you can read and i should be able to access my server at this URL so let me do another bash here curl of this URL it's not working because i get like a whole page that is not working because my server is not running okay we need to go run just a dot because we also have serve dot test allow and now i can go to my bash screen and i get a not found which is also normally showing here but this window is too small i think you see 404 not found so this was the first one that it was not running and now i get a 404 not found so this is working so now i just need to use this URL slash webhook and set up the webhooks in github so i'm going to go to my repository that i created i created a separate repository for this the go deploy kubernetes github and this one is private so that we can immediately also test this token first i'm going to create a webhook and then i'm going to create a file so webhooks and webhook slash webhook so this URL comes from ngrok the secret which i supply as an environment variable my secret enable asl verification should work because ngrok is doing the ssl for us which events you would like to trigger this webhook just a push event so if there's a push then it should trigger this webhook and webhook now the webhook is active should have this check mark next to it and i can add a file add file create new file and i'm going to use this app.yaml that i used in the previous lecture so this one is the kubernetes deploy app.yaml i'm just gonna copy paste this one this is the one i want to deploy i'll first give it a name and let me just check that my kubernetes cluster is empty that there's no deployment running kubernetes i'll get deploying there's no deployment running i'm not cheating going to test this webhook and i'm not sure even if it's gonna work i hope it'll work oh there is already something that happened here event not found oh yeah so when you create a webhook it creates an event so maybe it would be good to also capture this i didn't really think about that one case github hook oh yeah there's a hook and this is when the hook is created so then we can just say hook is created and then it will not say event not found hook is created and you would have to restart your server actually for this to work and then you would have to recreate the webhook if you want to have this nice output but just pushing the file now should trigger the webhook as well go deploy kubernetes github so this is where i configured the webhook this is a special repo that is empty best to keep it separate because otherwise you will just randomly push files to your kubernetes cluster you could add a filter on yaml and all these things if you want some more complexity and yeah this should be it commit let's try and let's have a look found files apple tml need an extra return here deploy of apple tml finished wow and we have now the 200 okay here let's have a look oops i'm opening too many windows oh and the deploy is there no it's not no it's pots and the pot is also there that's good news let's try to update our file and see that if we do an update that it also takes into account to update three replicas commit found files apple tml deploy apple tml finished so we now we have the second webhook and kubectl get pots pf3 pots so i kind of wrote a whole ci cd here in just a few lines because you also have ci cd systems that kind of take your git repository and then ingest these files and put them in kubernetes so that's kind of what we did now so we rewrote some of these systems that do that for you in kubernetes so this is our working version but then in the next lecture i'm going to have to move this within the cluster because we're still running outside our cluster with this ngrok if you then put it in the cluster then you can make it a complete service itself that runs within your kubernetes cluster and monitors your github repository to see if there are any files that need to deploy now that we successfully tested our github deploy locally i'm going to run it within a deployment on my kubernetes cluster so if you have another look to our main.ml these get client had the parameter files because we wanted to be not within the cluster so i'm going to change it to true and now it will expect us to be within the cluster so this code will be executed instead of the kube config another approach could be instead of this flag to check whether this file exists and if this file exists then we are outside the cluster if it doesn't exist then we are probably in the cluster and then you should load the incluster config that would also work so i'm just going to keep it simple now so get client true we are within the cluster gorun.go or gorun. will hopefully say something unable to load the incluster configuration kubernetes service host, kubernetes service port is not defined so these are the environment variables that it looks for and these are defined within the pod to then contact the kubernetes service it will contact the kubernetes service and if you contact the kubernetes service it's just the REST API and this REST API if you just contact it like that then you don't have any permissions to create pods or do anything so we will still need to give our pods permissions to create deployment and we can do that using a service account so let's have a look at this deploy.yaml this yaml definitions that I created to have our github deploy application the application that we wrote in the previous lecture to have deployed on a kubernetes cluster so if we start from the top we also have deployment I call it github deploy so we have the label app is github deploy one replica for now and we have a service account name so I will create a service account called github deploy and I will attach the permissions to it we have a container the name is github deploy and the image is wordfiana github deploy so if you want to deploy your own github deploy you will need a docker container repository you could use docker hub that's what I'm using and then this is your login of docker hub and then this is the repository so create this first this docker hub account and then you can build and push it to your docker hub account to have it available I'm going to show you in a second how we're going to build this docker container but you will need your own docker hub account to be able to push this image the port, I give it a name it's called the HTTP port you don't really have to give it a name but I gave it a name and the container port is 8080 because we run on 8080 I specify two environment variables because we don't really want to have it in our code that we're going to push to github so I set github token comes from a secret so we'll still have to create this secret the secret name is going to be github deploy and the key github token is webhook secret so what Kubernetes is going to do is it's going to have a look in this secret and inject these values in our bots so this is basically our deployment we would still need some other resources to get this working so we have another resource a service also called github deploy we say it needs to be on port 8080 and this is going to be how we're going to contact our application our github deploy outside our cluster because it is of type load balancer if you deploy this on AWS or Google Cloud with their Kubernetes offerings then this load balancer will in case of AWS create an AWS load balancer and then you will have a public host name that you can then configure as a webhook I'm going to use Minicube because that's the easiest way to run a development environment and you can still use load balancer in Minicube you just have to enter a command to tunnel this you can enter Minicube tunnel which I also will show you that will then create a link between your local machine and this service and then you can still use ngrok to expose it then we have the service account github deploy and then we have a role so this role is necessary to give us the correct permissions so we have this API group apps if you scroll down to our deploy you see client apps v1 this is actually apps API group and then the resource is deployments and this is our deployments here so this follows nicely the same structure and then the verbs that we are going to use get list watch create update patch delete it's a bit too much for what we need we use create update and also in this wait for pots we do a list but as an on the pots which I didn't give permissions for because we are not using it here but you could add it as well in that case the API group is empty and then we have the role binding so the role binding is going to link this role with this service account it's also called github deploy so it says the subject is the service account and the role is the github deploy so that's it we have the role binding to link those two, the service account and the role we have a service and then we have the deployment that also contains this service account name so it's linked with the service account and then we have the secrets so what do we still need to do we need to push our container and we need to create our secrets let's try to start with this container I have created a dockerfile here so this is a pretty generic dockerfile that is going to package our go lang program into a docker image so you need to have docker installed to be able to build this there's docker available for windows, mic and linux so you can just download and install it if you don't have it yet what are we going to do we're going to take the official go lang image we're going to download it we're going to use this as the go builder to create a new directory and cd into this directory is the github deploy directory we are going to use this is just to compile our program so to compile our program we need to copy everything from our current working directory everything that is right here into our container and we also have a docker ignore file and it's going to ignore the yaml definition and the git so we don't have to upload the git into our docker container then we're going to install curl and git because we need it for the go get to work and then we're going to build it because we are on alpine which is a slimmed down version it's still linux but we need to disable cgo so we just have a few flags here so that it works on alpine linux because this is the 118 alpine if you don't want to use alpine you can just remove this this alpine but then you wouldn't be able to use apk add because this apk add is specific to alpine if you remove this alpine and you have a normal linux distribution I think it's a debian based so you would have to use upcat so here we build it we build our go lang into a single binary using this line go build and our output will be github deploy so in the github deploy working directory we have file github deploy which is our binary then we're going to start another container just an alpine container so it's very minimal there's nothing in it and we're going to add CR certificates, bash and curl so these things are very handy for debugging and also CA certificates is necessary if you want to make outgoing calls and verify TLA certificates then we're going to say copy from the go builder this github deploy executable into slash github deploy so we'll just have one image file extra this file which is our executable and then when we start our container we'll execute this executable github deploy let's try to build this docker build I'm going to give it a tag and this tag is necessary to push it to my docker hub account let's have a look this needs to be the same docker build t word fiana github deploy and what do I want to build I want to build my current directory so I'm just going to put the dot now it's building and the build is finished so you see all the steps here my steps are cached because this is not the first time that I run it if I don't want to use a cache no cache which you don't need but I just want to show you the full output now you see downloading dependencies and installing everything and now the build will also take a little bit longer than the cached build and then if I would do a docker build again without this flag then it will go quicker again because now I already built it the next step is to push it to our docker hub this is docker hub hub.docker.com and then if you don't have an account yet you can create a new account here or you can sign in to sign in with your own account my account is hub.docker.com slash you slash wartviana and here you can see I pushed this github deploy I will push it again just to make sure that I have the latest version and then we can start using it so how do I push this image first you need to run docker login docker login will ask you the credentials for docker hub so that you can push your docker image to your own account so I do docker push and then the name of my image it will take this docker image that I just built and send it to github and now within our Kubernetes cluster we can use it so this will take a few seconds to get pushed the next step is to create these secrets to create these secrets you can use a kubectl command I rather use this github create secrets command than having them hardcorded in here because this deployable I'm then going to push to github so that way we can enter a command that is not visible in gith and then have still our definition in gith so this is finished let's try to start our minicube cluster and then create this secret so I need to start this minicube cluster always again because what I do is I do a minicube delete to then start from a clean minicube cluster so my minicube is running I'm going to create this secret create secret it's a generic secret so if you have a look at the help then you can create a docker registry a generic or tls so I'm going to create a generic one and then I'll make sure that this command is also in a readme in my github for this demo I need to enter these flags from literal and then key equals value so the webhook secret is my secret github token is this token that I just created again oh and then you also need to add a name so kubectl create secret generic and then the name is the github deploy because we refer here to the name and then it created a secret kubectl get secret if we then have a look at this secret then you see the actual input the data key value and the value is base64 encoded webhook secret and then again the value so this should work let's try to deploy this kubectl apply of this deployable this creates deployment the service account the role and the role binding one deploy one pot and one service how do we then access this service from our host system because this is of type load balancer we can use minicube tunnel and minicube tunnel create a tunnel between my host system and the service that is of type load balancer so if you are using minicube you can follow the same steps if you are on a real cluster then using this service load balancer will spin up a cluster that also gives you a host name that should be accessible starting tunnel for github deploy we need to keep this window open so i'm just going to open another bash window curl localhost 8080 page not found ok so this is our service within our Kubernetes that we are hitting now so let's now run ngrok again ngrok hp8080 and now ngrok instead of going to this local instance it will go to our minicube tunnel and our minicube tunnel will go to the service service will go to the pod and in the end we get to our real application this URL changed so i need to copy paste this again as a webhook go deploy Kubernetes github settings webhook i can delete my old webhook actually i didn't have to delete it i could have just updated it actually but it doesn't matter webhook secret is my secret just send the push event and then add the webhook and now i don't get the correct now i don't get the correct it just took some time so we did a post and yeah now the last delivery was successful let's have a look in the logs to be sure i'm going to open another window look we did our post gave us a 500 kubectl log get pods let's have a look in the logs there's nothing in the logs but the delivery was correct so let's continue and see what happens when we do the webhook there is still a possibility that i didn't that i didn't properly use this github hook or that we get a validated payload error because there is also backstab and missing here so let's just continue for now let's see how it goes code m.yml so if we trigger here a change then it will trigger our webhook so i made a change let's go and have a look in our webhook we can click on it recent deliveries okay so we have two and we can see the event you see so we have the repository the owner and so we have this commits array here it is commits where we have the modified apple.tml and we can then send this apple.tml to our Kubernetes cluster so let's have a look whether this worked or not kubectl get pods and yes i have my pods running kubectl get deploy and i have my deploy running there is just one pod let's try to run three of them then i just need to make one change in my code m.yml three replicas commit and now we have three and three pods let's now have a look at our logs kubectl get logs of this oh we still get this event not found that's why we had this 500 error kitabhook was the event not found maybe there is still something wrong here most likely the type is still of a different version so that's why it's not working and also it was not displaying it immediately because i also don't have a backstress N here these logs might not have shown if there was no new line but then when the webhook triggered we found the files and then we did the deploy so this is the most important here we definitely want to capture this first event but even if you don't capture this first event nothing is really going to happen i will try to update the correct code in my github repository so that you also have the correct code there it's probably going to be something small so now we have this working we have these logs here the deploy the webhook works we have ngrok that we have two times the states okay and we have the minicube tunnel that we set up for github deploy so we now really have our application running within Kubernetes and you can also go and have a look inside this pod by using kubectl-exec and then because we installed bash you can also enter bash and then we can have a look what is running here so we have this github deploy running and that's really our only binary that we have put in this image and the reason why it can contact our kubectl server is because we have somewhere these kubectl service defined and then if we curl to this IP address using hbs then you can see that we are actually well just clear screen for a second we can actually contact this API server and you see if you don't use any user then we have anonymous and then we get forbidden and that's why we needed this service account and this service account is then somewhere mounted within our pod run secret kubectl service account that's probably going to be it and then here we have the CA certificate and also we're going to have something to authenticate a token most likely or another certificate so that we can assume this service account we can connect to this API and then we have the role to do this getlist watch create update patch or delete and that's what this go SDK does for us so this get client here this rest in cluster config is going to take this environment variable and see if we can contact the Kubernetes cluster using this secret of our service account and that's why we don't have to do all these steps ourselves so that's it for this lecture if you're deploying this in a real cluster you're going to have a real host name that you can then use and expose your application and then you don't have to use and croc so the only downside here with minicube is that you have to use all of steps to get to your actual pod but if you would use a real production cluster then you don't need all these steps this was quite a long demo I hope when you try this demo yourself it also works for you if not reach out to me in the Q&A or send me a message


Very good welcome everyone So this is the talk about open source seriously You can choose whether there is a question mark or an exclamation mark after that Statement but I hope at the end of this presentation that you will all have an exclamation mark Or at least a dot sort of passive-aggressive dot There at the very end so just to Change around a little bit do the right branding Good, okay. It's the 17th of May everyone congratulations. It's the national day of Norway. I'm from Norway so that's really important and In Norway, that's a lot about children going in parades down the street waving flags We gave away all of our tanks to Ukraine. So that's Why we do the children? Would have been terrible to do the opposite So yes When we start a presentation, it's always good to start with the important stuff. So talking about myself, of course I am a tears bought lesniak and I am from just outside of Oslo in Norway. Norway is far away Right now. I'm based in Hawkes Bay, which is much closer. It's about an hour's flight four and a half hours drive from here in New Zealand and Also, the reason why I'm There right now is that my wife is a Kiwi and we're trying out New Zealand on our kids See if they get spots or something like that I've been working with typo 3 since 2003 when I crashed my first installation of that CMS I Can crash Drupal any day But yeah That you know, that's the way you learn you crash things and then you try to fix it afterwards My way to do that was to try to write my own CMS for about six months And that did not work out So I went back to type of three and now I'm a part of the type of three association board Which is not boring And I'm an open-source evangelist to do Working here in New Zealand so back to open source seriously Because this is going to be about open source on a fundamental level But before I do more about open source, I'm going to answer the question.  You've never heard about anything like that, right? Uh-huh Well, it's also free and open source totally unknown and It's community driven who's heard about that before and Yeah, it's backed by an association. How funny who does that? and It's got a long history. We're actually 25 years this year, so that's how long our history is and The point I'm trying to make here is of course that type of three is quite similar to Drupal if you look Below the surface because there is different concepts and there is different ways of doing things but really let's have a look just to to show you the real Similarity here, so I Took a look at you know, I downloaded the default base installation of Drupal and The default base installation of type of three so Drupal is in version 10. We just released type of three version 12 Yeah, we skipped version five for different reasons, so that's an unlucky number in the type of three world So Okay, if you look look at the dependencies in Drupal 10 There is 54 dependencies in a composer based install in Type of three. There's a little bit more. It's 98 dependencies That's we can discuss that for a very long time, but that's Just the number of dependencies, but the important thing that I want to show you today is that actually the similarities are Down at the bottom here We have 33 dependencies in common and If you look at older versions of of Drupal and type of three, there's even a little bit of type of three in Drupal it's gone now but see, we're really good friends actually and I think we should become better Friends and I'll show you why So this is Drupal and type of three, you know, usually when you talk to people from Drupal or type of three, it's a lot about you know, we're best and you know, they did all of those mistakes and ha ha Yeah, all of the things you hear from people who love Drupal and don't love type of three and the people who love type of three and absolutely hate, you know, that's not the right way of thinking We have so much in common and there's an important perspective to that as well Let's say that another CMS comes along as PHP based and open source and whatever. Let's call it Wordstar, right? and What sometimes happens with the open source Communities, you know, we look at them and we say, you know, they're new they've done something here We wouldn't have done it that way. We've been here 25 years but you know, suddenly it combusts and There is a huge security issue and we're like, huh, good We've been here for 25 years because we're you know, we wouldn't have done that, but you know now they're totally Yeah, out of the market, but Actually What happened to that CMS there? Actually very much affects us because there is a dark cloud Looming above us in the open source world. Yeah It's the proprietary vendors and do you know something about the proprietary vendors? Hmm They talk about open source as one they they're gonna say, you know Look at what happened with that security issue in open source. That's why you have to choose proprietary That's You know, don't choose Drupal. Don't choose type of three. Don't choose anything. That's open source And I mean, I still meet people at conferences where I say, you know, I'm from an open source CMS and they go Open source. Yeah, I tried that once Yeah, right So that really tells us what people See when they see our marketplace they very often choose between proprietary or open source in their mind and We need to be there too and we need to understand that this isn't a battle between Drupal and type of three or other Open source CMS is it's primarily About taking open source seriously so the first choice is When you get a new client or you talk to someone is Not Well, are you gonna choose Adobe or Drupal?  Let's say a site core. Yeah, or a type of three Proprietary no You know None of those are really good questions when you start with a client The real important Questions should be are you going to go for proprietary or open source? That is the battle we have to win together so When it comes to choosing a new system for your client, of course Choose open source Then You choose the CMS or the system that works for the client I know a lot of type of three sites that have been built because the agency knew type of three But type of three didn't actually fit for the client It's not good for open source when we just base ourselves on whatever platform we know and then It doesn't actually fit for the client That's bad marketing in the end because people go and say like this guy I met at a conference a month ago now who said, you know, yes, I tried open source and it didn't work Well, whose fault is that? Is that his fault? Or maybe He simply was introduced to the wrong tool Well, we have to ask ourselves those questions and then you choose the best agency and that's also something we very often forget that When we sell open source software, well, we don't sell open source software doing Well, we sell our expertise with the software and that is also important If you know that somebody can do things a lot better than you Maybe you should be honest and say that well, you know in my agency We work a lot with this kind of stuff We don't have experience with this maybe you would get the best result We're working with this agency or maybe you should simply collaborate And then I know some of you in the room here are asking, but why is Open source the obvious choice? Well, it's not only a technology choice And the reason is here in the desert Well, everyone the desert is a very good picture of close source It's a mono culture sand and It creates dependence whoever owns the watering hole Owns the people right It's the only place you can go to get water That's a proprietary way of thinking on the other hand we have Open source Well, open source is diversity to the extreme of course, but it really Points to giving people freedom That's why we say free and open source You have the freedom to make what you want There is no dependence here But if you look at the biology here, there is of course interdependence. Well, we share dependencies, right? There is interdependence between Drupal and type of three. So when you compare these two You know the water hole owner Well, once you know where the water hole is it's easy for you as long as you have no problem with the water hole owner You can just lean back and relax, right? Well Open source Doesn't always make it easy, but it asks something from you it asks you to make the change that you want to see and I Well, this is you Well, imagine that this is your garden, right? You've been redoing your house or something Your problem here is that you don't have a car or at least not a pickup or a youth It's cold around here, but you have a friend who has right so you call up your friend and use this Oh God, oh my garden is looking like this, you know Can you come and help me with your car and we'll drive it off to the dump and clean up your friend says yeah, sure Of course, I'll do that with you well When you're finished you might you know Give your friend a few dollars to cover petrol or something the cost of enablement But you're not going to ask Your friend is not going to ask you to pay him or her by the hour Right because that's what friendship is about It's a kind of love, right and it very much describes open source as well We just give something away without expecting something that we might actually ask for a payment for the download for the enablement But it's really there for free. It's a type of love and it's really Unconditional love which is really nice a nice thought. It's not the sticky kind of love, it's it's a different kind of love and That has to be a conscious effort to think that way when you work with open source Open source takes more than one person. It takes you and a friend it takes you on multiple friends and it requires a number of things it requires commitment contribution community and cooperation to really work You can't lean back with open source, but it asks something of you And I think that's actually a really healthy question and a lot of what you guys do in your open source community is also what we could call development corporation You cooperate about development. Well development corporation is another word That's also used outside in the rest of the world, but it means something slightly different It means What you might call development aid? Right, but it's not it's not aid. It's cooperation. It's working together and In the type of three association we had an experience with that the difference between aid and cooperation and It all began with a phone call Yeah, that's how our phones look We got a phone call from the random government Hmm, you get a lot of those well It was real and they said hi, we've got 250 type of three Installations they're old. We need to upgrade them. Can you help us? We said oh Sure But how are we gonna do that? Are we gonna do well? We could you know recommend an agency that we've got Ask them to make a proposal. It's gonna cost us in that much and They'll get the stuff done But then we thought you know is that the open-source way Because very often when it comes to this kind of thing it starts out That this is actually the way that a lot of governments promote helping Developing countries today You take an established business that opens a local office in The developing country and then they earn lots of money and they export it, right? because that's what the business is about when you do it from a business perspective and You get all of these things that you actually what you're doing is That you're building dependencies you're building a desert Where someone comes in and they can take the whole market because they rich they have millions in marketing, right? Well, if you look at that from a historical perspective that is both Colonialist and exploitative Because it doesn't really take the best out of the country that you're in and use it there You just take out the money and place it somewhere else so we thought How can we do that from the open-source spirit? Well, what we thought was that we could use our community our open-source community to create Independent local business and expertise in Rwanda that is different. So we talked to our member agencies and We asked them to donate time we paid travel and food and stuff to Rwanda and we sent our experts down to train Local web agencies to help their government Upgrade their website This is how it looked was a number of trips down to to Rwanda to do this So basically the government in Rwanda Could use their money to pay their taxpayers To do a job for them instead of paying someone from the outside and we gave away our expertise This is the result. It's not up at 270 websites. There will probably be about 500 in the end and if you look at this as a Newspaper headline. I'm sure it's not going to be like this in a in a newspaper basically the essence of what we did is that we took our Democratic and not-for-profit open-source project and used it to support sustainable and independent local business and from the perspective of fighting Colonialism and exploitation and those kind of things there's three words here that are important one is that it was locally led so it wasn't someone coming in and Doing it for anyone there. It was locally led so it based itself in The place where it was done. It was also non-exploitative and It was anti-colonial and when you talk to aid Workers and NGOs about that they Go like ah, yes but For us. There's actually one other word here that is much more important for for our project and that is Community because community is what we want to grow as an open-source project We want to not have more people have websites made by existing agencies. We want more agencies to work with open-source and being in a community Also has some really important values connected to it. If you're in a community you have to be your best Otherwise the community will not work if you're in a community You have to deal with stuff like governance and a good way to do governance in the community is also democracy for example and Governance Working with interests in a community. That's also something that is called civil society I'll get back to that But that's what community does when you have to collaborate. You can't just be dependent. You have to be active yourself so The values of open-source it turns out are actually the values of a healthy society an open-source is actually Civil society it's a part of civil society and If you wonder about what civil society is and the importance of it Well, let me just say one thing about civil society civil society won the Nobel Peace Prize last year That is where open-source connects in to the greater Society and the reason why I'm talking about this is because we can continue doing open-source as sort of our little island But if we really think about what open-source really means Look at the world today Democracy is under attack. There's a lot of things happening that are working against these community values that we also work with and when you work with open-source you're training yourself in Doing the right thing for your country and your local community. So you're actually strengthening civil society here in New Zealand and Australia wherever you live By working with open-source in a community with other people and that is Why we should really take open-source seriously Not only as something that we use but as the community that we're a part of and look beyond our individual projects and See all of the connection points that we have to other open-source projects Because by working together and understanding the value of that That is how we can really fight proprietary software with open-source Thank you. So the question is how do I see competing open-source CMS is finding Well, they're why they're way to exist in the market without destroying each other Well, I think you know Back to the picture of the desert We don't want a monoculture because it would be just as bad if There was a monopoly on type of three or on Drupal in the world that would not drive Development really and it would not benefit the people who they after they work on the dependencies that Rcms is dependent And I think You know, yes, there is a kind of competition, but I like to point to the agencies more on that. I mean What expertise can you bring in That will make Drupal work for your client in the best possible way That is the real question and Then we have to be frank with each other and say that well there are definitely projects for type of three and there's projects for Drupal and The other CMS would not really work as a good solution for that and on the other side in some cases You have to say that well both can solve the same problems. Well Then you have to look to the agencies you have to look at the expertise and say well Who is here who can solve this question in the best possible way and then Apart from that, I think we should forget about the competition part and I think we should collaborate because we Well, it's not a good argument to say, you know, Drupal is better than Adobe Because there's so many more values and open source that if you choose open source for all of your solutions and your government or in your business That's going to have benefits beyond your technical website solution right and I think that we need to get together to support our upstream providers to make sure that what we're building up our software on is actually good and solid and supported and we have to take our Communities and learn from each other because that's also something that can come from the proprietary world that you know They've got a crappy community. Well, we have to learn community best practices and help each other Become communities that can really really make good software Because that's the way We're all gonna win in the open source world by cooperation So the answer is how we can Can I short question? Well, the the proprietary systems have a lot of marketing money, for example, we do not and how can we work with that? Well, of course, it's everybody's dream to have a lot of money You know, if you're not a member of the Drupal Association, for example become one It's a great way to support your open source project and help them actually do marketing on your behalf But on the other side, we have these values. There are much bigger than just the business and if it's something that you can talk about that's bigger than your project Talking about values is a way to get into government talking about values as a way to get into corporations because they Also want to mostly do the best for their citizens do the best for their clients do the best for the world and That means that we also have some arguments that are unique to the way we work and instead of fighting Proprietary software on the well who's got the most security holes in their system? Well, you can't say that about proprietary systems because you can't look into them, right? So that's a very very hard fight to fight but if you talk about values and talk about how Open source is really a part of a really positive movement in the world You've got something you can talk about that goes way beyond what? the proprietary software can So that's my answer sort of but yes money everyone wants money But yes become a member of the Drupal Association support open source. That's important Yeah, so that's the question of you know how How do I relate to to love when it comes to software open-source software being put out there, but then being exploited by rich Corporations that just take and take and take and never give back You know, we're always going to have that happen and at the same time by talking about the importance of giving back we're actually Changing some minds making a little bit of progress on that it's always going to be a fight But if we stop talking about the important part of giving back then it's never gonna happen and There is nothing wrong, you know in sitting there at home and downloading an open-source piece of software and not paying for it if you don't know About open source it's nothing wrong about not having money and not paying for You know a developer who wants to attend a conference. There's nothing wrong in that but there's a difference between consciously choosing not to and not knowing and That's why we need to talk about open source Because it also makes a pressure on these corporations to actually give something back and The when I talk to people who don't know open source. I often use the example of the cooking recipe Let's say that you have a really great cooking recipe and You make food for someone and they say wow, this is a great recipe Can I have it from you and you say yeah sure I'll write it down and you give it to someone and There's two things that can happen that person starts a you know burger chain or whatever and Says that you know I've got the world's best burgers and that person does not say that this burger recipe is actually from you The other way to do it the more open-source way is to say that well, you know a month later you come back to To me and give me my recipe and say that well, you know, I made this improvement If you add this or remove that it's going to be so much better and That is the community working because the community contributions actually make the software better by just Taking the software and using it. You're actually not improving it and That hurts you in the end as well