top of page

Language Flashcards from Songs and Movies - Part 6: A Separately-Deployable Micro UI

  • Writer: Derek Ferguson
    Derek Ferguson
  • Nov 30, 2019
  • 9 min read

I ended my last post having created a "Hello World" page that is getting served up from a Node (Express) processing running behind Istio. In this post, I'd like to turn that base piece into a micro front-end container, then add in a UI for my flashcard-generating interface as a Web Component.

Since it has been 3 weeks since I last looked at this, I'm going to start by getting back to where I left off. I open a browser and head to http://192.168.7.34:31380. Of course, it doesn't work (why aren't I surprised). My theory is going to be that all the additional Istio monitoring I installed after my app probably broke it somehow or another, but I'll start from the point of my initial deploy in my last blog post and work forward from there.

Actually, it turns out I didn't have to go that far. We had some power outages here and all of my servers were off. Turning them back on resolved the issue. :-) Sometimes software development is JUST that easy. :-)

I avail myself of the opportunity to run a quick "sudo apt-get update" and "sudo apt-get upgrade" on all the machines in my cluster, to bring K8S up to 1.16.3 on all my machines. That all goes smoothly.

My plan is to use a very simple web component container - just a variation on the last example shown in this blog. Before I do that, though, I want to change my serving app to send this content up from static files in "public".

I try to deploy this with a simple "helm install ./cards-ui-service/," but it gives me an error saying that I need to provide a name or use a "--generate-name" option. I guess this is something new in this version of Helm? Whatever -- I provide that switch and it starts the deploy, but errors out saying that one resource already exists. Maybe my upgrade reset the Helm database but left the K8S pieces out there for my last deploy?

I use "kubectl delete" to delete the pod, the service, the virtual service and the gateway, then rerun "helm install ./cards-ui-service/ --generate-name" and it deploys. I'm very happy, but then I see that the same UI is still running as before. I'm not quite sure how this is possible, if everything got updated as I thought. I have to figure this out next.

Of course, I soon remember that this is all based on Docker images and never rebuilt and pushed the relevant docker image. So, I do that and retry - after doing a "helm delete" and another helm install, as per above. The static content is served up, as desired. Perfect!

I then copy/paste the HTML from the blog above exactly as it read - knowing that it won't work, because it defines a bunch of Web Components that don't yet exist, and give it a whirl. Whirl, in this case, meaning building the Docker image, then removing and redeploying via Helm. I am happy to see the new static content being produced and, as expected, errors for all the Web Components it wasn't able to find.

So, let's modify the source code to reference just 1 component (for starters), and that will be our Russian text Web Component - served up by a completely different service!

First, I change the location from whence the script for the 1 remaining component will come. I use a relative URL and tell it to try to retrieve it from the stem "/russian/bundle.js". Then I change the name of the component to be "russian-text."

I redeploy, to make sure that the breakage has changed as expected. One thing I've learned as a part of this process: it is good to wait maybe 30 seconds after a "helm delete" before a "helm deploy" on my system, as it seems to take about that time for the underlying K8S resources to truly be removed. Anyhow - the retry produces exactly the desired results: there is only 1 error now instead of 3, and inspecting it reveals that it is looking for the component at exactly the right place - a "/russian" directory back on its server of origin, where I will (hopefully) be able to map the Istio gateway to a completely separate service.

I don't have the Vue pieces, so I start with "npm install -g @vue/cli", to get the Vue CLI. Everything seems to install perfectly, but I'm reminded at the end that I am 4 versions behind current for npm, so I upgrade that after Vue, but before trying it.

It has been remarked that so much of the difficulty in programming is naming things properly, and I'm really wishing I hadn't called what has morphed into my container "flashcardsui." If I had it to do over again - or could easily do it now - I'd probably just call it "container," but fine. So, I create a peer folder to "flashcardsui" and called it "russian-text", to remind me exactly what this component need to be called.

Looking at my previous component (the container) - I'm thinking my new component can have all the same files... all I should really have to change up (at first) is the content of the static HTML. So, let's start by creating all the same high-level stuff: a Dockerfile and a Node JS Express app that serves up some static content.

I want to follow the instructions in this article to actually create a Web Component in Vue JS, so it seems to me that the code for my VueJS stuff should be separate from the Node stuff. So, I take everything I created in the previous step and sweep it into a top-level folder called "node" and run my VueJS CLI command ("vue create vue", because I'm just going to call its main folder "vue") to create the VueJS app at the same level as that folder to create a sibling sub-folder to contain just my VueJS.

I take the defaults on the Vue CLI creation and since it is the first time through, it needs to download some stuff. So, it does that and continues through to the end without an issue. To help you visualize the structure, here is a screen capture.

Following along with the Vue article I referenced above, I start by changing my main.js file to create a component called "russian-text". I also note that it wants to work with a component called "VueWebComponent" instead of the "HelloWorld" Vue component that the CLI created, so I delete the created component and add a new VueWebComponent.vue file to the components folder.

Into this file, I paste the sample code from the article above. I want to change as few things as possible until we are up-and-running with this all served via Istio. I'm thinking let's focus on the infrastructure first - which is experimental, then we can circle back to the actual content, which is more of a blazed path.

At this point, I try to run the "vue-cli-service" command, but it says that it can't find it. :-( . I get sick after a few minutes of trying to get it to run directly from the command line, and decide to follow the instructions in this article to run it using npx instead. I get npx by simply doing "npm install npx -g".

After going through this, I thnk that they're only doing this to build the component, which I think can be done via a simple "npm run build". However, I run both command variants: "npm run build" and "npx vue-cli-service build --target wc --name russian-text ./src/main.js" and see that only the later variant allows me to name the component "russian-text," which is going to be essential, so I go with that.

I'd like to see if I can verify this in any way, shape or form before struggling with the Istio portion of serving it. I notice that there are commands to serve this up built into the package, and the "deploy" directory after building it has some demo HTML, so - let's spend a minute seeing what it might take to prove this out on our development machine.

I run "npm run server" and after futzing for a while, I realize that I can simply paste the sample code from the "dist" directory created when I ran "npm run deploy" into the "index.html" under the public subfolder and there's my site. However, since the Vue CLI had no way of knowing my web component takes a parameter called "msg", so I add that in as an attribute on my "russian-text" attribute and - there it is!

So, with that... I am as convinced as I think I can be that we've created a proper Web Component. Let's get started service it up via Istio!

So, I run "npx vue-cli-service build --target wc --name russian-text ./src/main.js" one more time in the "vue" subdirectory and look at the "dist" directory it populates. Looks to me like I just need to re-add that "msg" parameter, copy it over to the "public" directory of my "node" subdirectory, package into Docker, work out the Helm deployment and go from there. Simple! :-)

I just move "demo.html" and the "russian-test.js" file it references directly over to the public directory under "node" in Visual Studio - since the "dist" directory (rightly) isn't a part of source control, anyhow. Then I run "docker build -t dotnetderek/russian-text ." in that directory with no problems, followed by "docker push dotnetderek/russian-text:latest". Finally, it occurs to me I can do an additional level of checking by running "docker run -p 9095:9095 dotnetderek/russian-text:latest" and then browsing to http://localhost:9095. Sure enough - I see my web page there with the web component. So... I feel I've proven we have a good Docker image here.

The one thing that DOES disturb me is that I haven't changed the port number. I don't know what the potential ramifications of that might be, but I don't want any conflicts, so I decide to bump it down. I look through all the YAML in the templates directory of the HELM deployment as it stands and only see 9095 and 9094, so, I'm thinking I'll bump it down by 1000, to 8095. I change that in the Dockerfile and in the index.js of the Node process, repackage and re-run the Docker... and all is perfectly smooth!

I start down the path of creating a second copy of each of the YAML files in the templates directory - figuring that I will modify them to do the same thing for our new Web Component that the previous files did for the container HTML. App.yaml makes sense in this context. But the second file I get to is gateway.yaml, and that appears to be a universal - so I leave it alone.

I duplicate and modify service.yaml and do the same for virtualservice.yaml. It looks to me like the Virtual Service is where the completely separate new app I've created is mapped onto the shared gateway, based on its URL stem. We'll see shortly!

I push all of our changes up to Bitbucket, then pull them down on the hub in my cluster (which also has all the Helm pieces on it). I delete the existing deployment, wait 30 seconds, then run my usual chart deployment command. Wait 30 seconds and try the various URL's. First, let's try the previous URL - everything still looks the same at root (/) on port 31380.

What about /russian-text? Well, I get an error - from Node, it seems - telling me that it can't GET that. I look at it for a bit and think about the fact that when I pulled it up directly from Docker on my development machine, I had to reference that demo.html page. I should rename the page to be the default, so I don't have to put a page behind the stem. "index.html" appears to be the standard, so I try that (meaning, rename, repackage and redeploy).

That doesn't help, so I'm wondering... what if I put it in a directory under "public" called "russian-text"? After all, any string other than that after the stem is causing a general error, so clearly Node is listening at least! I try it locally and "/russian-text" now serves up something - so maybe we can get the same behavior from the Gateway on the K8S cluster. Everything seems to break badly at this point - I can't even tell the difference between going to "/russian-text" and going to "/random-garbage". So... that appears to be a misstep.

Trying to put it back the way it was yields the same results. :-( Now I am a bit panicked... can't seem to get back to where I was before.

After struggling for a while, I come to the conclusion that I need to do a remapping from some kind of different stem in the URL to the root path that the Docker image (and Node code) wants.

I pair this with a change in the index.html to look for the backing javascript using the "/russiantext" stem, and ... now I can pull up the demo page for my web component!

So now, the final question is: can I add this component to my separately-served container app living at the root of the cluster's URL space? I change the index.html of my container to use the same "russian-text" url stem to grab the JavaScript for my component and... it works!

So - we now have the flexibility to put whatever we like on that component and deploy it completely separately. We'll fill it out in the next episode of the blog!

 
 
 

Comments


  • Facebook
  • Twitter
  • LinkedIn

©2018 by Machine Learning for Non-Mathematicians. Proudly created with Wix.com

bottom of page