<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniel</title>
    <description>The latest articles on DEV Community by Daniel (@danieltanfh95).</description>
    <link>https://dev.to/danieltanfh95</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F453368%2F2f9a75c9-3d0f-4748-abdf-db0cd1a4e1e7.jpeg</url>
      <title>DEV Community: Daniel</title>
      <link>https://dev.to/danieltanfh95</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danieltanfh95"/>
    <language>en</language>
    <item>
      <title>Nobody on the internet knows if you are a human</title>
      <dc:creator>Daniel</dc:creator>
      <pubDate>Thu, 28 May 2026 12:27:44 +0000</pubDate>
      <link>https://dev.to/danieltanfh95/nobody-on-the-internet-knows-if-you-are-a-human-19i2</link>
      <guid>https://dev.to/danieltanfh95/nobody-on-the-internet-knows-if-you-are-a-human-19i2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fen%2Ff%2Ff8%2FInternet_dog.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fen%2Ff%2Ff8%2FInternet_dog.jpg" alt="A dog at a keyboard tells another dog: 'On the Internet, nobody knows you're a dog.'" width="299" height="334"&gt;&lt;/a&gt;&lt;br&gt;Cartoon by Peter Steiner, &lt;em&gt;The New Yorker&lt;/em&gt;, July 5, 1993.
  &lt;/p&gt;

&lt;p&gt;Technology is progressing to the point where it is getting increasingly harder to tell if someone is a bot or a human. LessWrong ironically uses LLM tools to tell LLMs apart from humans. On the internet nobody knows if you are a dog, or a LLM-inspired human. This is nothing new: David Chaum published "Security without Identification: Transaction Systems to Make Big Brother Obsolete" in 1985 to argue that we should build identity systems without actually learning who someone is — to which the internet responded by collectively using username+passwords to build account identities, then got surprise-Pikachu'ed when bots fought through anyway via Sybil attacks.&lt;/p&gt;

&lt;p&gt;The present situation is that the Internet is actively hostile towards good actors (presumed to be humans at this point) through a combination of CAPTCHAs, accounts requiring logging in via your email and your mom's birthday, or 2FA that requires a trusted third party (often mega-corporations) to escort you into the website, all while being friendly to automation through unofficial APIs or web scraping. Computer use in LLMs has largely slammed the door shut on traditional methods of preventing bots.&lt;/p&gt;

&lt;p&gt;The other approach that largely turned out to be security theater was &lt;a href="https://anubis.techaro.lol/" rel="noopener noreferrer"&gt;Anubis&lt;/a&gt;, which proudly proclaimed itself the watchdog of the internet, weigher of souls, but in the words of its creator "Over time I thought the proof-of-work was actually doing something for security, but no — any barrier makes the low-effort scrapers confused and give up." Really, the rapid FOSS adoption (200k downloads to date) has largely just rehashed Hashcash and propagated anime cat girls throughout the internet, besides actively calling out Mozilla as the benevolent god of bots (except that it is not only trivial to bypass, it ignores &lt;code&gt;curl&lt;/code&gt;). As it turns out, the more valuable your website, the higher the floor of computation you need to use, but at some point you have to pay latency debts back, so you have a ceiling where this works out. People abandoned Hashcash for good reason, it burdens legitimate users while doing nothing to bots who wants to squeeze you for value and provide nothing back.&lt;/p&gt;

&lt;p&gt;The mistake here is largely treating bots (or "clankers" in the ongoing debate between &lt;a href="https://lucumr.pocoo.org/2026/5/24/pi-oss/" rel="noopener noreferrer"&gt;boomers&lt;/a&gt; and &lt;a href="https://lucumr.pocoo.org/2026/5/26/clankers/" rel="noopener noreferrer"&gt;clankers&lt;/a&gt; that's also indicative of the entire misguided approach to this) as "all bad" and humans as "all good". Bots are a tool that are driven by other humans to leech off your website. I also hate the contrived name "clanker" when we have a perfectly good name for irresponsible agents: bots, which is short, catchy, and has been in use for a long time.&lt;/p&gt;

&lt;p&gt;What we want are really to filter bad from good agents (AI or humans alike) with a third party "substrate" that is independent of our ability to think (as you can see, trying to split AI from humans via the capability and capacity to think has largely ended up in spectacular failure and a total waste of time and resources).&lt;/p&gt;

&lt;p&gt;And we already have it. It is called time. &lt;/p&gt;

&lt;p&gt;For example, it is perfectly acceptable to be suspicious of someone who has moved into your neighbourhood, and similar that person would be suspicious of others in the neighbourhood. It would be weird, in fact, if that person acted overly friendly to people, and vice versa. However, as time passes with normal-to-positive interactions between both parties, respect is earned between both parties, more trust is allocated, and thus more openings, more information is available. &lt;/p&gt;

&lt;p&gt;Hacker News works the same way: a new account can't downvote or flag until it has earned karma because privileges accrue with proven history, not at signup. Time is the passive, all-knowing, self-historical substrate we can operate trust on.&lt;/p&gt;

&lt;p&gt;This is just common sense we can apply here, and that is what I am doing with &lt;a href="https://github.com/danieltanfh95/continuity-auth" rel="noopener noreferrer"&gt;Continuity Auth&lt;/a&gt;: treat all newcomers as suspect, and identify them via patterns, not names. This is Chaum's 1985 thesis applied to the rate-limiter (security without identification), instead of the attester model his blind-signature lineage grew into (Privacy Pass, Apple's Private Access Tokens), where a third party vouches for you. Here there is no attester and no web-of-trust to concentrate power in a mega-corporation: trust is built directly between you and the service by behaving consistently over time.&lt;/p&gt;

&lt;p&gt;More importantly, this raises the cost of bot farms by making Sybil attacks uneconomical: genuine users (human or AI) engaging in good faith will happily wait for time to pass, while bot farms must maximise value-per-compute or they lose money, so "sit still and behave for two weeks" is the one cost they can't parallelize away.&lt;/p&gt;

&lt;p&gt;In continuity-auth, I provide a multi-tier model: the more identity you provide, the higher the initial trust afforded, but you still join a time-gated suspect test until you are time-proven to be a good actor.&lt;/p&gt;

&lt;p&gt;The trust signal itself borrows from my exploration in &lt;a href="https://danieltan.weblog.lol/2026/04/time-flies-in-the-ai-world-my-agent-lineage-evolution-ale-framework-in-2025-was" rel="noopener noreferrer"&gt;succession&lt;/a&gt; of how human memory "actually works". We treat historical writings with much more weight than what has happened recently, especially when said writings have recent analogues. Instead of rewarding whoever shows up the most, we reward whoever stayed the longest, by weighing spaced recurrence over massed frequency. Volume is cheap to manufacture, calendar time is not, which is exactly the asymmetry a bot farm cannot buy its way out of.&lt;/p&gt;

&lt;p&gt;Real alignment begins between humans and LLMs when we build for good actors, not make grand claims that are time-proven to be wrong, time and time again.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>privacy</category>
      <category>security</category>
    </item>
    <item>
      <title>Pragmatic Programming Understanding</title>
      <dc:creator>Daniel</dc:creator>
      <pubDate>Fri, 18 Sep 2020 10:28:33 +0000</pubDate>
      <link>https://dev.to/danieltanfh95/pragmatic-programming-understanding-2dm7</link>
      <guid>https://dev.to/danieltanfh95/pragmatic-programming-understanding-2dm7</guid>
      <description>&lt;p&gt;I’m taking a break from my usual articles to write something for beginners starting to program: Brief, simple explanations of various concepts and programming terms. These came from explaining some concepts to my friend who was completing a curriculum in computer science.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features vs Design vs Implementation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Features: What the program can do&lt;/li&gt;
&lt;li&gt;Implementation: How the program does it&lt;/li&gt;
&lt;li&gt;Design: Planning features and implementations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Programming paradigms
&lt;/h2&gt;

&lt;p&gt;In programming we have logic (how), and data (what). Do note that these paradigms can be mixed.&lt;/p&gt;

&lt;p&gt;Functional paradigm: It’s when you pass in data into logic, and have a new data as a result. E.g. Clojure.&lt;/p&gt;

&lt;p&gt;Object Oriented paradigm: It’s when you place logic in data, and data uses signals to communicate between each other on what logic to trigger. E.g. Ruby&lt;/p&gt;

&lt;p&gt;There are also paradigms that focus on what to control, the logical command or the logical result.&lt;/p&gt;

&lt;p&gt;Imperative paradigm: You make logical commands that describe logic to change your data. E.g. C.&lt;/p&gt;

&lt;p&gt;Declarative paradigm: You explain the final data result to program and it solves the commands to do it for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types
&lt;/h2&gt;

&lt;p&gt;Untyped languages are like maths. You focus on getting the algorithms right. Here we use schemas to restrict the range of data that can be correct. E.g. square root, but following schema of positive integers. This includes Python and Ruby.&lt;/p&gt;

&lt;p&gt;Typed languages are like physics, you focus on getting the results right. Here types perform basic checking on intermixed values. For more complex checking to the level of schemas you need dependent types. This includes C and Haskell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutability
&lt;/h2&gt;

&lt;p&gt;Mutable means “can be changed. Immutability, the opposite, can prevent more human errors by making sure data can only be copied, but not changed. However, the trade off is that your program takes more space and is slower.&lt;/p&gt;

&lt;p&gt;On the other hand, programs using mutable data structures can be very fast and use less memory but programmers will make more mistakes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project management
&lt;/h2&gt;

&lt;p&gt;Scope: How much will you complete&lt;/p&gt;

&lt;p&gt;Resources: How much can you use (including human resources)&lt;/p&gt;

&lt;p&gt;Time: How long will you take&lt;/p&gt;

&lt;p&gt;This brings us to the development styles:&lt;/p&gt;

&lt;p&gt;Waterfall: Fixed scope, but flexible resources and time.&lt;/p&gt;

&lt;p&gt;Agile: Fixed resources and time but flexible scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spectrum of development
&lt;/h2&gt;

&lt;p&gt;All of these require algorithm and data structure knowledge.&lt;/p&gt;

&lt;p&gt;Front-end: User-facing application where you have less control over the environment. Can be web based, like HTML/JS/CSS, or native, like C++ or Java.&lt;/p&gt;

&lt;p&gt;Back-end: Non-user-facing application where you have more control over the environment. Any language can be a backend language.&lt;/p&gt;

&lt;p&gt;Infrastructure and Operations: Applications that host the front-end or back-end applications, and how to transfer the front-end application to the user etc&lt;/p&gt;

&lt;p&gt;Data engineering: Applications that gather and clean data for use in other applications like AI applications.&lt;/p&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>Awesome Unity3D: State Machines — Effective State Management</title>
      <dc:creator>Daniel</dc:creator>
      <pubDate>Thu, 27 Aug 2020 15:08:50 +0000</pubDate>
      <link>https://dev.to/danieltanfh95/awesome-unity3d-state-machines-effective-state-management-3gdm</link>
      <guid>https://dev.to/danieltanfh95/awesome-unity3d-state-machines-effective-state-management-3gdm</guid>
      <description>&lt;p&gt;This article assumes you know what are Finite State Machines (FSM). If not, I would recommend reading this article that &lt;a href="https://gameprogrammingpatterns.com/state.html"&gt;shows common pitfalls when writing code handling character state and why we use FSMs&lt;/a&gt;. If you prefer a "TL;DR", the gist is that without FSMs you need to use plenty of flags in your program, which can lead to many nested "if-else" statements everywhere, leading to a terrifying debugging experience. You do not want to waste your time in this self-made hell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example of self-made hell&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleInput&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKeyDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KeyCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Space&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;isJumping&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isDucking&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Jump...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKeyDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KeyCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;isJumping&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;isDucking&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;setGraphics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMAGE_DUCK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetKeyUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KeyCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isDucking&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;isDucking&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;setGraphics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMAGE_STAND&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;FSMs are the kind of pattern that most people I know have a love/hate relationship with. Love it for it's ability to encapsulate dynamic application state, hate it for additional complexity. Personally I did not enjoy using code-only FSMs since juggling state transitions can be quite a handful especially in games with complex interactions between units but including a GUI solution for FSM like Playmaker can be pretty heavy. &lt;/p&gt;

&lt;p&gt;On that note, what if there is a lightweight FSM system that we can use (or hijack) within Unity? &lt;/p&gt;

&lt;h2&gt;
  
  
  Using the &lt;code&gt;AnimationController&lt;/code&gt; as FSM
&lt;/h2&gt;

&lt;p&gt;Unity already contains a state machine for animations that we can use, with some modification.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UBCiz4M9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/696/0%2Axis_tqpYGqI2LuMJ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UBCiz4M9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/696/0%2Axis_tqpYGqI2LuMJ" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create an empty GameObject in the scene with an Animator attached.&lt;/li&gt;
&lt;li&gt;Create a new AnimatorController asset somewhere in your project folder. Attach this to the Animator you've created.&lt;/li&gt;
&lt;li&gt;Open Window→Animator→Parameters and create a trigger called "Next".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j6ayyQ9g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2Ag-wsnFt3ztW-8wU-" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j6ayyQ9g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2Ag-wsnFt3ztW-8wU-" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Customization
&lt;/h3&gt;

&lt;p&gt;Create a class that inherits  &lt;code&gt;StateMachineBehaviour&lt;/code&gt; so we can create custom states, provide a cleaner interface for the state machine, and enable debugging. We can call our custom class &lt;code&gt;LogicalStateMachine&lt;/code&gt; . &lt;code&gt;StateMachineBehaviour&lt;/code&gt; already provides methods such as &lt;code&gt;OnStateEnter&lt;/code&gt; , &lt;code&gt;OnStateUpdate&lt;/code&gt; , &lt;code&gt;OnStateExit&lt;/code&gt; , which we can use to provide interfaces such as these.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnLogicalStateEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnLogicalStateUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnLogicalStateExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ResetState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnStateEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AnimatorStateInfo&lt;/span&gt; &lt;span class="n"&gt;stateInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;layerIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;ResetState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;OnLogicalStateEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnStateUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AnimatorStateInfo&lt;/span&gt; &lt;span class="n"&gt;stateInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;layerIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;OnLogicalStateUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnStateExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AnimatorStateInfo&lt;/span&gt; &lt;span class="n"&gt;stateInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;layerIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;OnLogicalStateExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To make it easier to debug, we'll use the trigger we've created before to create a &lt;code&gt;Continue&lt;/code&gt; method that can force the next state to occur.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Continue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StringToHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnStateEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AnimatorStateInfo&lt;/span&gt; &lt;span class="n"&gt;stateInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;layerIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ActiveAnimator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;animator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;ResetState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ResetTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StringToHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nf"&gt;OnLogicalStateEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveAnimator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can make this even better by creating an Inspector Button for it in the editor. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3C292SFz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1388/0%2ANzNajE5m_SJyIjdo" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3C292SFz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1388/0%2ANzNajE5m_SJyIjdo" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Personally I just use the Odin Inspector to create one but if you'd prefer a native solution there's one &lt;a href="https://raw.githubusercontent.com/zaikman/UnityPublic/master/InspectorButton.cs"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Voila! A simple state machine you can use in your project. You can find the code here as well: &lt;a href="https://gitlab.com/glassblade/unityfsm"&gt;https://gitlab.com/glassblade/unityfsm&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Effective State Management in Games
&lt;/h2&gt;

&lt;p&gt;This advice applies to most complex applications, but game is a good example. Games typically contain two types of state : persistent state and dynamic state. For example, in the game, "Enter the Gungeon", the persistent state would contain the unlocked pool of guns, while the dynamic state would contain the gun picked up by the player.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iGPiXHMm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2AwyZvd2vCDP2GevEo" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iGPiXHMm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/0%2AwyZvd2vCDP2GevEo" alt="Enter the Gungeon gameplay"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FSMs contain two basic components, state and transitions and I would recommend the following to make it easier to debug your state in FSM:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you need to use a flag, don't. Use a state instead.&lt;/li&gt;
&lt;li&gt;Spending some time before you code to identify what would be persistent state and dynamic state in your game relative to the FSM. Dynamic state should be reset each time you enter a state while persistent state will not.&lt;/li&gt;
&lt;li&gt;Make an immutable copy of your persistent state on entering a state, only set persistent state on exiting a state. You can optimize this later on, but it makes it alot easier for debugging points of error.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>unity3d</category>
    </item>
    <item>
      <title>Pragmatic K8s Understanding</title>
      <dc:creator>Daniel</dc:creator>
      <pubDate>Sun, 16 Aug 2020 03:19:50 +0000</pubDate>
      <link>https://dev.to/danieltanfh95/pragmatic-k8s-understanding-fm1</link>
      <guid>https://dev.to/danieltanfh95/pragmatic-k8s-understanding-fm1</guid>
      <description>&lt;p&gt;This article simplifies k8s as a magical tool to simplify deployment. By the end of the article you should have enough basic knowledge to discuss k8s with others, and to use it as well.&lt;/p&gt;

&lt;p&gt;This article is also part of a Machine Learning Ops (MLOps) series.&lt;/p&gt;

&lt;p&gt;But before we start, an image describing the experience of learning k8s right now in spite of the resources widely available in the web, which prompted me to write an article that follows the &lt;a href="https://en.wikipedia.org/wiki/KISS_principle"&gt;KISS principle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IR_xuEOf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.redd.it/3pdbnh698pu41.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IR_xuEOf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.redd.it/3pdbnh698pu41.jpg" alt="https://i.redd.it/3pdbnh698pu41.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Why kubernetes (k8s)?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UIeoJKvh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2Amcn_dC3qSZ5mkFX7" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UIeoJKvh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2Amcn_dC3qSZ5mkFX7" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember when during development you only have one machine to deploy with, and you're asked to scale your application without much budget? Naturally. you set up a load balancer and create two instances with different ports to handle the extra load. Later on, you're given more computers, and you do the same thing on those computers as well. This becomes a tedious task as more and more computers are required, and it's still not an easy task even with tools like Ansible.&lt;/p&gt;

&lt;p&gt;What k8s does is automating away all of this, so most of the times after you set up k8s, all you need to do is register your new computer with labels of apps that are allowed on it, and k8s takes care of the rest. On a single computer, it handles load balancing and ports automatically for your applications when scaling up, all without bundles of bash/Ansible scripts, which brings us to the next great feature of k8s.&lt;/p&gt;

&lt;p&gt;Writing k8s configuration files are pretty much like writing SQL code whereas tools like Ansible are similar to writing Python code. You just describe what you want, and k8s finds the best way to do it. Since the config are just YAML files, you can keep it with your repository as well. Updating the deployment is as easy as updating the configuration files and applying it to the cluster.&lt;/p&gt;

&lt;p&gt;This means you can bring your application to multiple different clusters in different environment and expect more or less similar behaviour, which makes it very attractive for a lot of companies.&lt;/p&gt;

&lt;p&gt;However, k8s requires containers to do its magic, so before I proceed to provide a simple guide to k8s, I have to explain containers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why containers?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HU_GZz2L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/850/0%2AQXZveqr1zRs5Zo1Z" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HU_GZz2L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/850/0%2AQXZveqr1zRs5Zo1Z" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nuff' said.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Actual Guide
&lt;/h1&gt;

&lt;h2&gt;
  
  
  K8s terms translator
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Node: Computer that is not a container.&lt;/li&gt;
&lt;li&gt;Cluster: Group of nodes.&lt;/li&gt;
&lt;li&gt;Control plane: Node that controls other nodes.&lt;/li&gt;
&lt;li&gt;Persistent Volumes: A description of what storage is available.&lt;/li&gt;
&lt;li&gt;Persistent Volume Claims: A description of what storage you need.&lt;/li&gt;
&lt;li&gt;Pods: A description for how containers are run and how they use persistent volumes.&lt;/li&gt;
&lt;li&gt;Deployment: A group of pods.&lt;/li&gt;
&lt;li&gt;Service: A description for how deployments communicate through the internet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Using k8s
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://minikube.sigs.k8s.io/docs/start/"&gt;Minikube&lt;/a&gt; has, by far, the easiest way to start with k8s on a single computer. &lt;/li&gt;
&lt;li&gt;Otherwise, the second easiest is to get one from Azure, AWS or GKE.&lt;/li&gt;
&lt;li&gt;Finally it would be setting up a cluster manually using kops, kubeadm or kubespray. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  K8s essentials for developers
&lt;/h2&gt;

&lt;p&gt;There's really four basic concepts you need to know before using k8s: containers, persistent storage, deployments, services.&lt;/p&gt;

&lt;p&gt;We'll use Nginx for this example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Containers (Docker)
&lt;/h3&gt;

&lt;p&gt;You'll have to be able to create a docker image. I wrote an article on how to &lt;a href="https://medium.com/glassblade/strategies-for-reducing-docker-image-size-with-python-flask-feef86a63349?source=your_stories_page---------------------------"&gt;reduce docker container size&lt;/a&gt; that would be useful as well, which also contains a sample docker file used to build the image.&lt;/p&gt;

&lt;p&gt;Do note that containers can be restarted or destroyed often, for example when your container crashes k8s will automatically restart it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Persistent Storage
&lt;/h3&gt;

&lt;p&gt;The easiest to start with local data, but there are &lt;a href="https://kubernetes.io/docs/concepts/storage/storage-classes/"&gt;many other types as well&lt;/a&gt;. This type of storage will not be destroyed when the container is destroyed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolume&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-pv&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;storageClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manual&lt;/span&gt;
  &lt;span class="na"&gt;capacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10Gi&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteMany&lt;/span&gt;
  &lt;span class="na"&gt;hostPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/lib/path-in-node"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A persistent volume only describe what storage is available, it does not actually allocate the storage or block it off. &lt;/p&gt;

&lt;p&gt;You can use access modes to describe the behaviour of pods when dealing with this storage (i.e. mounting). &lt;em&gt;This is irrespective of the actual file system&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;There are three modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ReadWriteOnce : the volume can be mounted as read-write by a single node&lt;/li&gt;
&lt;li&gt;ReadOnlyMany : the volume can be mounted read-only by many nodes&lt;/li&gt;
&lt;li&gt;ReadWriteMany : the volume can be mounted as read-write by many nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deployments
&lt;/h3&gt;

&lt;p&gt;This describes an actual "application". It uses containers and persistent storage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-vol&lt;/span&gt;
        &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-pvc&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:latest&lt;/span&gt;
        &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-vol&lt;/span&gt;
          &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/lib/path-in-nginx-container&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As noted, you can start with multiple replicas of your application. The deployment will create multiple copies of your pods using the template. &lt;/p&gt;

&lt;h3&gt;
  
  
  Services
&lt;/h3&gt;

&lt;p&gt;You can expose your app to the internet using services. You can choose a load balancer between multiple nodes or just use a port on a node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30080&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The service automatically load balances between pods created by a deployment.&lt;/p&gt;

&lt;p&gt;The service selects deployment based on the app label specified in the deployment (i.e. the selector). &lt;/p&gt;

&lt;p&gt;Services, by default are only allowed to use ports 30000-32767. You can use another reverse proxy or ingress to do port forwarding, common options are Nginx and HAProxy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;And that's basically most of what you need to actually be productive in k8s.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>containers</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
