<?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: Blake Covarrubias</title>
    <description>The latest articles on DEV Community by Blake Covarrubias (@blakec).</description>
    <link>https://dev.to/blakec</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%2F172955%2F3090abd0-7bba-4430-a33d-80869b68a9b3.jpeg</url>
      <title>DEV Community: Blake Covarrubias</title>
      <link>https://dev.to/blakec</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/blakec"/>
    <language>en</language>
    <item>
      <title>Exploring the HelmChart custom resource in k3s</title>
      <dc:creator>Blake Covarrubias</dc:creator>
      <pubDate>Sun, 08 Sep 2019 18:24:40 +0000</pubDate>
      <link>https://dev.to/blakec/exploring-the-helmchart-custom-resource-in-k3s-2l52</link>
      <guid>https://dev.to/blakec/exploring-the-helmchart-custom-resource-in-k3s-2l52</guid>
      <description>&lt;p&gt;&lt;a href="https://k3s.io/" rel="noopener noreferrer"&gt;k3s&lt;/a&gt; is a lightweight &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; distribution developed by &lt;a href="https://rancher.com/" rel="noopener noreferrer"&gt;Rancher&lt;/a&gt; which is suitable for edge, IoT, and resource-constrained computing environments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; is a package manager for Kubernetes which enables users to find, share, and use software built for Kubernetes.&lt;/p&gt;

&lt;p&gt;Traditionally, Helm is comprised of a client (&lt;code&gt;helm&lt;/code&gt;) and server-side component, &lt;a href="https://helm.sh/docs/glossary/#tiller" rel="noopener noreferrer"&gt;Tiller&lt;/a&gt;, which manages the deployment and lifecycle of Helm charts. In k3s, Tiller is replaced by &lt;a href="https://github.com/rancher/helm-controller" rel="noopener noreferrer"&gt;Helm Controller&lt;/a&gt;. Helm Controller defines a new &lt;code&gt;HelmChart&lt;/code&gt; &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/" rel="noopener noreferrer"&gt;custom resource definition&lt;/a&gt;, or CRD, for managing Helm charts.&lt;/p&gt;

&lt;p&gt;You can verify the &lt;code&gt;HelmChart&lt;/code&gt; resource is present on a k3s cluster by using &lt;code&gt;kubectl&lt;/code&gt; to list the available API resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt; $&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;k3s kubectl api-resources &lt;span class="nt"&gt;--api-group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;helm.cattle.io
&lt;span class="go"&gt;NAME         SHORTNAMES   APIGROUP         NAMESPACED   KIND
helmcharts                helm.cattle.io   true         HelmChart
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  The HelmChart resource
&lt;/h2&gt;

&lt;p&gt;Below is an example of a &lt;code&gt;HelmChart&lt;/code&gt; resource definition.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;helm.cattle.io/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;HelmChart&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Kubernetes object metadata&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Chart name (required)&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kube-system&lt;/span&gt; &lt;span class="c1"&gt;# Namespace Helm Controller is monitoring to deploy charts (required)&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# resource specification&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;apiVersion&lt;/code&gt; and &lt;code&gt;kind&lt;/code&gt; fields together identify this as a HelmChart resource to be managed by Helm Controller.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; field under &lt;code&gt;metadata&lt;/code&gt; specifies a name for the HelmChart resource. &lt;code&gt;namespace&lt;/code&gt; specifies the &lt;a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/" rel="noopener noreferrer"&gt;Kubernetes namespace&lt;/a&gt; in which Helm Controller is monitoring CRDs. For k3s, this must be &lt;code&gt;kube-system&lt;/code&gt; as Helm Controller is only configured to watch this namespace for new HelmChart resources.&lt;/p&gt;

&lt;p&gt;Lastly, the &lt;code&gt;spec&lt;/code&gt;, or &lt;em&gt;specification&lt;/em&gt;, field is used to specify the desired state of the HelmChart resource.&lt;/p&gt;
&lt;h3&gt;
  
  
  HelmChart resource &lt;code&gt;spec&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The HelmChart resource supports several configuration &lt;a href="https://github.com/rancher/helm-controller/blob/3e223ca9dc94607ea9b7deb7f632551230c4db32/pkg/apis/helm.cattle.io/v1/types.go#L20-L25" rel="noopener noreferrer"&gt;parameters&lt;/a&gt;. These parameters correspond to &lt;code&gt;helm install&lt;/code&gt; command line arguments and are passed to Helm during chart deployment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;chart&lt;/code&gt; (string: null) - Chart reference or a URL.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;targetNamespace&lt;/code&gt; (string: null) - Namespace to install the Chart into. Defaults to the namespace used by the k3s controller (i.e., kube-system) if omitted.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;version&lt;/code&gt; (string: null) The exact Chart version to install. If this is not specified, the latest version is installed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;repo&lt;/code&gt; (string: null) - Chart repository URL where to locate the requested Chart.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;set&lt;/code&gt; (string: null) - A dictionary/map consisting of configuration values to provide to Helm. Keys should be specified as strings. Values may be either Integers or Strings. If more complex values are required, use &lt;code&gt;valuesContent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;valuesContent&lt;/code&gt; (string: null) - A list of configuration values to provide to Helm. This should be a multi-line string.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is an example of a HelmChart resource definition with all available configuration values defined.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;helm.cattle.io/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;HelmChart&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;example-helmchart&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kube-system&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;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-helmchart&lt;/span&gt;
  &lt;span class="na"&gt;targetNamespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-namespace&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.1&lt;/span&gt;
  &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://example.com/helm-charts&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;key1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value1"&lt;/span&gt;
    &lt;span class="na"&gt;key2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value2"&lt;/span&gt;
  &lt;span class="na"&gt;valuesContent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
    &lt;span class="s"&gt;config:&lt;/span&gt;
      &lt;span class="s"&gt;application:&lt;/span&gt;
        &lt;span class="s"&gt;admin_username: admin&lt;/span&gt;
        &lt;span class="s"&gt;admin_password: insecure_password&lt;/span&gt;
      &lt;span class="s"&gt;server:&lt;/span&gt;
        &lt;span class="s"&gt;port: 8080&lt;/span&gt;
        &lt;span class="s"&gt;tls_enabled: false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The corresponding CLI arguments for this would be:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;test-helmchart &lt;span class="nt"&gt;--namespace&lt;/span&gt; test-namespace &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="go"&gt;                              --version 0.0.1 \
                              --repo https://example.com/helm-charts \
                              --set-string key1=value1 \
                              --set-string key2=value2 \
                              --values values.yaml
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Where values.yaml contains the content present under the &lt;code&gt;valuesContent&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Both &lt;code&gt;set&lt;/code&gt; and &lt;code&gt;valuesContent&lt;/code&gt; may be used to configure the chart. &lt;code&gt;set&lt;/code&gt; only supports strings or integers as values. If other data types are needed, use &lt;code&gt;valuesContent&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating a HelmChart
&lt;/h2&gt;

&lt;p&gt;We will now walk through the process of creating a HelmChart resource definition to deploy &lt;a href="https://nodered.org/" rel="noopener noreferrer"&gt;Node-RED&lt;/a&gt; – a flow-based programming for the Internet of Things.&lt;/p&gt;

&lt;p&gt;The following steps were performed on a Raspberry Pi 4 running the &lt;a href="https://en.wikipedia.org/wiki/Raspbian" rel="noopener noreferrer"&gt;Raspian&lt;/a&gt; operating system. You may need to modify the commands if using a different environment.&lt;/p&gt;

&lt;p&gt;First, create a file named &lt;code&gt;node-red-helmchart.yaml&lt;/code&gt; using your default editor.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;editor node-red-helmchart.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Copy and paste the following block of text into the file.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;helm.cattle.io/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;HelmChart&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;node-red&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kube-system&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;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stable/node-red&lt;/span&gt;
  &lt;span class="na"&gt;targetNamespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-red&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image.tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rpi&lt;/span&gt;
  &lt;span class="na"&gt;valuesContent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
    &lt;span class="s"&gt;ingress:&lt;/span&gt;
      &lt;span class="s"&gt;enabled: "true"&lt;/span&gt;
      &lt;span class="s"&gt;annotations:&lt;/span&gt;
        &lt;span class="s"&gt;kubernetes.io/ingress.class: traefik&lt;/span&gt;
        &lt;span class="s"&gt;traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip&lt;/span&gt;
      &lt;span class="s"&gt;hosts:&lt;/span&gt;
        &lt;span class="s"&gt;- raspberrypi1.local&lt;/span&gt;
      &lt;span class="s"&gt;path: /node-red/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;Note: Be sure to modify the &lt;code&gt;ingress.hosts&lt;/code&gt; field to contain the hostname and/or IP address of one or more node in your Kubernetes cluster.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The deployment of the chart has been customized by modifying several of the available &lt;a href="https://github.com/helm/charts/tree/master/stable/node-red#configuration" rel="noopener noreferrer"&gt;configuration values&lt;/a&gt;. Particularly, Ingress support has been enabled which exposes Node-RED to hosts outside of the Kubernetes cluster at &lt;a href="http://raspberrypi1.local/node-red/" rel="noopener noreferrer"&gt;http://raspberrypi1.local/node-red/&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installing a HelmChart
&lt;/h2&gt;

&lt;p&gt;There are two methods to install a HelmChart in k3s.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the resource definition using &lt;code&gt;kubectl apply&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Copy the resource definition to the server's manifest directory at &lt;code&gt;/var/lib/rancher/k3s/server/manifests/&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Installing via kubectl
&lt;/h3&gt;

&lt;p&gt;Instruct Kubernetes to install the specified resource definition using &lt;code&gt;kubectl apply&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;k3s kubectl apply &lt;span class="nt"&gt;--filename&lt;/span&gt; node-red-helmchart.yaml
&lt;span class="go"&gt;helmchart.helm.cattle.io/node-red created
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is the standard method of provisioning resources within Kubernetes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Installing using Auto-Deploying Manifests
&lt;/h3&gt;

&lt;p&gt;k3s includes a feature called &lt;a href="https://rancher.com/docs/k3s/latest/en/configuration/#auto-deploying-manifests" rel="noopener noreferrer"&gt;Auto-Deploying Manifests&lt;/a&gt; which allows for the automated deployment of Helm charts (and Kubernetes manifests) placed in k3s manifest directory (&lt;code&gt;/var/lib/rancher/k3s/server/manifests&lt;/code&gt;). Helm Controller continually watches this directory for new CRDs. When it detects a new resource has been added, it will automatically deploy the chart. Therefore, you can initiate the installation by simply copying &lt;code&gt;node-red-helmchart.yaml&lt;/code&gt; into the server's manifest directory.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo cp &lt;/span&gt;node-red-helmchart.yaml /var/lib/rancher/k3s/server/manifests/node-red-helmchart.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Installation process under the hood
&lt;/h3&gt;

&lt;p&gt;Regardless of the installation method used, when a chart is deployed Helm Controller creates a Kubernetes &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/" rel="noopener noreferrer"&gt;Job&lt;/a&gt; which installs the chart into the cluster using &lt;code&gt;helm install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Execute &lt;code&gt;kubectl get jobs&lt;/code&gt; in the kube-system namespace and search for Jobs associated with the deployed chart.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;k3s kubectl &lt;span class="nt"&gt;--namespace&lt;/span&gt; kube-system get &lt;span class="nb"&gt;jobs&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="go"&gt;                   --selector helmcharts.helm.cattle.io/chart=node-red
NAME                    COMPLETIONS   DURATION   AGE
helm-install-node-red   0/1           21s        23s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can view the command the Job is executing by re-running &lt;code&gt;kubectl get jobs&lt;/code&gt;, and appending additional arguments to select and display Job-specific information using kubectl's &lt;a href="https://kubernetes.io/docs/reference/kubectl/overview/#custom-columns" rel="noopener noreferrer"&gt;custom-column&lt;/a&gt; output.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CUSTOM_COLUMN_OUTPUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"COMMAND:.spec.template.spec.containers[0].name,INSTALL_ARGS:.spec.template.spec.containers[0].args"&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;k3s kubectl &lt;span class="nt"&gt;--namespace&lt;/span&gt; kube-system get job helm-install-node-red &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="gp"&gt;                   --output=custom-columns=$&lt;/span&gt;CUSTOM_COLUMN_OUTPUT
&lt;span class="go"&gt;COMMAND   INSTALL_ARGS
helm      [install --name node-red stable/node-red --namespace node-red --set-string image.tag=rpi]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The Job installs the chart by executing &lt;code&gt;helm install&lt;/code&gt; with the list of installation arguments provided in the HelmChart resource, as noted earlier.&lt;/p&gt;
&lt;h3&gt;
  
  
  Verifying the chart installation
&lt;/h3&gt;

&lt;p&gt;Verify the chart has been successfully deployed by ensuring the associated resources have been created within the node-red namespace.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;kubectl &lt;span class="nt"&gt;--namespace&lt;/span&gt; node-red get ingress,service,pods
&lt;span class="go"&gt;NAME                          HOSTS                ADDRESS      PORTS   AGE
ingress.extensions/node-red   raspberrypi1.local   10.0.0.133   80      2m2s

NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
&lt;/span&gt;&lt;span class="gp"&gt;service/node-red   ClusterIP   10.43.135.177   &amp;lt;none&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;1880/TCP   2m2s
&lt;span class="go"&gt;
NAME                            READY   STATUS    RESTARTS   AGE
pod/node-red-7c5c564cb6-sz8b8   1/1     Running   0          2m1s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Updating a HelmChart
&lt;/h2&gt;

&lt;p&gt;The configuration for a chart may be updated using &lt;code&gt;kubectl apply&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;k3s kubectl apply &lt;span class="nt"&gt;--filename&lt;/span&gt; node-red-helmchart.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Deleting a HelmChart
&lt;/h2&gt;

&lt;p&gt;To delete a Helm Chart, use &lt;code&gt;kubectl delete helmchart&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;k3s kubectl &lt;span class="nt"&gt;--namespace&lt;/span&gt; kube-system delete helmchart node-red
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You have learned about the HelmChart custom resource available in K3s, how to construct a HelmChart resource definition, install it on the cluster, and perform post-deployment operations (update/delete).&lt;/p&gt;

&lt;p&gt;That's it for this walkthrough.&lt;/p&gt;

&lt;p&gt;I have a written program, &lt;code&gt;k3s-helmchart-generate&lt;/code&gt;, which simplifies the process of building HelmChart manifests. You can find a link to the repo on GitHub below.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/blake" rel="noopener noreferrer"&gt;
        blake
      &lt;/a&gt; / &lt;a href="https://github.com/blake/k3s-helmchart-generate" rel="noopener noreferrer"&gt;
        k3s-helmchart-generate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Helper script to generate HelmChart CRDs for use with k3s
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>k3s</category>
      <category>helm</category>
      <category>rancher</category>
    </item>
    <item>
      <title>Installing OpenWrt onto a TP-Link TL-MR3020 router via a serial port from macOS</title>
      <dc:creator>Blake Covarrubias</dc:creator>
      <pubDate>Tue, 03 Sep 2019 18:33:23 +0000</pubDate>
      <link>https://dev.to/blakec/install-openwrt-onto-a-tp-link-tl-mr3020-router-via-a-serial-port-from-macos-b3i</link>
      <guid>https://dev.to/blakec/install-openwrt-onto-a-tp-link-tl-mr3020-router-via-a-serial-port-from-macos-b3i</guid>
      <description>&lt;p&gt;This is a tutorial for using macOS to install &lt;a href="https://openwrt.org/"&gt;OpenWrt&lt;/a&gt; on a &lt;a href="https://www.tp-link.com/uk/home-networking/3g-4g-router/tl-mr3020/"&gt;TP-Link TL-MR3020&lt;/a&gt; router via a serial port from the CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Target audience
&lt;/h2&gt;

&lt;p&gt;This tutorial is targeted toward individuals possessing basic to intermediate Linux expertise, and who own a TL-MR3020 which is either bricked (i.e., firmware does not load), or to which they do not possess the administrative credentials required to login and flash the firmware from the web interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You will need the following items in order to successfully complete the instructions outlined in this tutorial.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A macOS computer&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://www.tp-link.com/uk/home-networking/3g-4g-router/tl-mr3020/"&gt;TP-Link TL-MR3020&lt;/a&gt; router&lt;/li&gt;
&lt;li&gt;1 x USB UART adapter (e.g., &lt;a href="https://www.adafruit.com/product/954"&gt;Adafruit Industries 954 USB to TTL Serial Cable&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;1 x &lt;a href="https://www.amazon.com/AmazonBasics-USB-2-0-Cable-Male/dp/B00NH13S44/"&gt;USB A-Male to Mini-B charging cord&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;1 x &lt;a href="https://www.adafruit.com/product/994"&gt;Category 5 (CAT5) Ethernet cable&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Male to male jumper wires (e.g., &lt;a href="https://www.adafruit.com/product/1956"&gt;Adafruit Industries 1956 Premium Male/Male Jumper Wires - 20 x 3" (75mm)&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Internet access&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1 - Prepare the environment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Configure a static IP on your Ethernet interface
&lt;/h3&gt;

&lt;p&gt;In order to copy the firmware from your computer to the router you must first configure an IPv4 address on your computer's Ethernet interface so that it may communicate with the router when connected.&lt;/p&gt;

&lt;p&gt;To configure an IP on macOS, go to System Preferences &amp;gt; Network and select your Ethernet interface. Click on the dropdown next to Configure IPv4 and select the option 'Manually'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5lIlKUGO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jaeq2ivo1u9h6i2fxzsm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5lIlKUGO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jaeq2ivo1u9h6i2fxzsm.png" alt="macOS manual IPv4 address configuration on Ethernet" width="880" height="742"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure an IPv4 address such as 192.0.2.2 with a subnet mask of 255.255.255.0.&lt;/p&gt;

&lt;p&gt;Click Apply to save the configuration.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This address will not be accessible on your primary network. It will be used solely for communication with the router.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KPxIH-f---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9qb4c06la042omxoh0hl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KPxIH-f---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9qb4c06la042omxoh0hl.png" alt="Configuring a static IP on macOS" width="880" height="762"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Download the OpenWrt firmware
&lt;/h3&gt;

&lt;p&gt;Head over to OpenWrt's website to download the latest, supported release firmware for the &lt;a href="https://openwrt.org/toh/tp-link/tl-mr3020#installation"&gt;TL-MR3020&lt;/a&gt;. Be sure to download the link under the column entitled Firmware OpenWrt Install URL.&lt;/p&gt;

&lt;p&gt;At the time of writing, the current supported release is &lt;a href="http://downloads.openwrt.org/releases/17.01.5/targets/ar71xx/generic/lede-17.01.5-ar71xx-generic-tl-mr3020-v1-squashfs-factory.bin"&gt;17.01.5&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure the TFTP server
&lt;/h3&gt;

&lt;p&gt;In order to copy the firmware to the device, you will need to set up a &lt;a href="https://en.wikipedia.org/wiki/Trivial_File_Transfer_Protocol"&gt;Trivial File Transfer Protocol (TFTP)&lt;/a&gt; server. This server will be used by the router to download the firmware from your computer.&lt;/p&gt;

&lt;p&gt;macOS ships with a TFTP server in the base installation. Use the following &lt;code&gt;launchctl&lt;/code&gt; command to temporarily enable the TFTP server under macOS' service manager, &lt;a href="https://en.wikipedia.org/wiki/Launchd"&gt;launchd&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;launchctl load &lt;span class="nt"&gt;-F&lt;/span&gt; /System/Library/LaunchDaemons/tftp.plist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The daemon will automatically start upon receiving a network connection request to the computer's IP on either TCP/UDP port number 69 –– the standard TFTP port number.&lt;/p&gt;

&lt;p&gt;Next, copy the firmware downloaded in the previous step to the TFTP server's data directory, &lt;code&gt;/private/tftpboot/&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo cp&lt;/span&gt; ~/Downloads/lede-17.01.5-ar71xx-generic-tl-mr3020-v1-squashfs-factory.bin /private/tftpboot/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 - Open the device
&lt;/h2&gt;

&lt;p&gt;The top of the router comes off with a bit of prying. Insert a plastic tool to carefully pry open the plastic top.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2irkQz_u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ywgafjvh0scax1nkqmx5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2irkQz_u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ywgafjvh0scax1nkqmx5.jpg" alt="Prying open the top of a TP-Link TL-MR3020 with a screwdriver" width="601" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Connect the USB adapter to the UART pins on the router
&lt;/h2&gt;

&lt;p&gt;Plug the USB adapter into your computer.&lt;/p&gt;

&lt;p&gt;Next, connect the transmit, receive, and ground wires from the UART adapter to the associated pins on the router which are highlighted in the following picture just below the RAM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DXo7g5c1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/551qgtguwihf3xemvc6c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DXo7g5c1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/551qgtguwihf3xemvc6c.jpg" alt="TL-MR3020 UART pin location" width="880" height="1174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The order of the pins from left to right is: Power, Ground (GND), Receive (RXD), and Transmit (TXD).&lt;/p&gt;

&lt;p&gt;Using the jumper wires, connect the cables from the USB UART adapter to the UART pins on the router's board. The resultant connections should be:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TL-MR3020&lt;/th&gt;
&lt;th&gt;USB-UART&lt;/th&gt;
&lt;th&gt;COLOR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GND&lt;/td&gt;
&lt;td&gt;GND&lt;/td&gt;
&lt;td&gt;BLACK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RXD&lt;/td&gt;
&lt;td&gt;TXD&lt;/td&gt;
&lt;td&gt;GREEN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TXD&lt;/td&gt;
&lt;td&gt;RXD&lt;/td&gt;
&lt;td&gt;WHITE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Note: Be sure to swap the TXD and RXD when connecting to the router.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tMnzqdiU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0hrg04yhuz029w6p03h5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tMnzqdiU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0hrg04yhuz029w6p03h5.jpg" alt="Jumper connections to UART connections on TL-MR3020" width="880" height="1174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Connect the Ethernet cable to the router
&lt;/h2&gt;

&lt;p&gt;Connect the Ethernet cable between your computer and the router's Ethernet port.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 - Initiate a console connection to the router
&lt;/h2&gt;

&lt;p&gt;Open a Unix console on macOS using a terminal emulator such as the built-in Terminal application (Applications &amp;gt; Utilities &amp;gt; Terminal) or &lt;a href="https://www.iterm2.com/"&gt;iTerm2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, use the &lt;code&gt;cu&lt;/code&gt; command which is built into macOS to initiate a console connection from your computer to the router. Alternatively, you can use a GUI-based serial console program such as &lt;a href="https://freeware.the-meiers.org/"&gt;CoolTerm&lt;/a&gt; or &lt;a href="https://www.decisivetactics.com/products/serial/"&gt;Serial&lt;/a&gt; from DecisiveTactics.&lt;/p&gt;

&lt;p&gt;You will need to provide &lt;code&gt;cu&lt;/code&gt; the name of your TTY device, and a &lt;a href="https://en.wikipedia.org/wiki/Baud"&gt;baud&lt;/a&gt; rate of 115200 bits per second to use for the connection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cu &lt;span class="nt"&gt;--line&lt;/span&gt; /dev/tty.SLAB_USBtoUART &lt;span class="nt"&gt;--speed&lt;/span&gt; 115200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will not see any output on your screen until the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 - Power on the router
&lt;/h2&gt;

&lt;p&gt;Connect the USB A end of your USB cable to either a USB wall charging adapter or a second USB port on your computer.&lt;/p&gt;

&lt;p&gt;Connect the mini-B end of your USB cable to the USB port on the router. You should see text output on your terminal screen from the router's boot loader as the router boots.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;U-Boot 1.1.4 (Aug 17 2012 - 15:21:03)

AP121 (ar9330) U-boot

DRAM:  32 MB
led turning on for 1s...
id read 0x100000ff
flash size 4194304, sector count = 64
Flash:  4 MB
Using default environment

In:    serial
Out:   serial
Err:   serial
Net:   ag7240_enet_initialize...
No valid address in Flash. Using fixed address
No valid address in Flash. Using fixed address
: cfg1 0x5 cfg2 0x7114
eth0: 00:03:7f:09:0b:ad
ag7240_phy_setup
eth0 up
: cfg1 0xf cfg2 0x7214
eth1: 00:03:7f:09:0b:ad
athrs26_reg_init_lan
ATHRS26: resetting s26
ATHRS26: s26 reset done
ag7240_phy_setup
eth1 up
eth0, eth1
Autobooting in 1 seconds
&lt;/span&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="c"&gt;# Booting image at 9f020000 ...&lt;/span&gt;
&lt;span class="go"&gt;   Uncompressing Kernel Image ... OK

Starting kernel ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before the router boots the kernel, quickly type &lt;code&gt;tpl&lt;/code&gt; into the terminal to access the U-Boot console.&lt;/p&gt;

&lt;p&gt;There is a very short window in which to type the aforementioned keys before the router begins booting the operating system. You may need to reboot the router, and make multiple attempts to successfully enter the keystrokes.&lt;/p&gt;

&lt;p&gt;If successfully entered, you will see the following U-Boot prompt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Fun fact: The TL-MR3020 uses the ALFA Network Hornet-UB embedded board, hence the name 'hornet' in the boot loader's prompt.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7 - Download the firmware onto the router
&lt;/h2&gt;

&lt;p&gt;In order to download the firmware onto the router you must configure an IP address for the router, and set the TFTP server IP as the IP address of your computer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;setenv ipaddr 192.0.2.10
&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;setenv serverip 192.0.2.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, use the &lt;code&gt;tftpboot&lt;/code&gt; command to download the firmware from the TFTP server to the router. The command takes several argument options.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tftpboot [loadAddress] [bootfilename]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Execute the following to download and install the OpenWrt firmware.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tftpboot 0x80000000 lede-17.01.5-ar71xx-generic-tl-mr3020-v1-squashfs-factory.bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see output similar to the following if the router is able to connect to router computer and successfully download the firmware.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tftpboot 0x80000000 lede-17.01.5-ar71xx-generic-tl-mr3020-v1-squashfs-factory.bin
&lt;span class="go"&gt;Using eth1 device
&lt;/span&gt;&lt;span class="gp"&gt;TFTP from server 192.0.2.2;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;our IP address is 192.0.2.10
&lt;span class="go"&gt;Filename 'lede-17.01.5-ar71xx-generic-tl-mr3020-v1-squashfs-factory.bin'.
Load address: 0x80000000
&lt;/span&gt;&lt;span class="gp"&gt;Loading: #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;################################################################&lt;/span&gt;
&lt;span class="gp"&gt;         #&lt;/span&gt;&lt;span class="c"&gt;#####################################################&lt;/span&gt;
&lt;span class="go"&gt;done
Bytes transferred = 3932160 (3c0000 hex)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make note of the hexadecimal value indicating the number of bytes transferred - in this case, &lt;code&gt;0x3c0000&lt;/code&gt;. This value will be needed later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8 - Install the firmware onto the router's flash memory
&lt;/h2&gt;

&lt;p&gt;Next, use the &lt;code&gt;erase&lt;/code&gt; command to erase the existing flash memory. The &lt;code&gt;help&lt;/code&gt; command can be used to provide the syntax of the &lt;code&gt;erase&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;help &lt;/span&gt;erase
&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;erase start +len
    - erase FLASH from addr 'start' to the end of sect w/addr 'start'+'len'-1
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The console output "Booting image at 9f020000 ..." in Step 6 shows the router's current firmware is located at memory address 0x9f020000.&lt;/p&gt;

&lt;p&gt;You will need to erase a sufficient amount of space starting from this address to fit the size of the new firmware. Recall the bytes transferred value saved from Step 8. This value will be used as the the &lt;code&gt;+len&lt;/code&gt; offset in the &lt;code&gt;erase&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Execute the following command to erase the flash firmware. You should see the subsequent output upon successful deletion of the specified memory range.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;erase 0x9f020000 +0x3c0000
&lt;span class="go"&gt;
First 0x2 last 0x3d sector size 0x10000
  61
Erased 60 sectors
&lt;/span&gt;&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, use &lt;code&gt;copy.b&lt;/code&gt; to install the downloaded firmware onto the router's flash memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;help &lt;/span&gt;cp.b
&lt;span class="go"&gt;cp [.b, .w, .l] source target count
    - copy memory
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cp.b 0x80000000 0x9f020000 0x3c0000
&lt;span class="go"&gt;Copy to Flash... write addr: 9f020000
done
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 9 - Boot the OpenWrt OS
&lt;/h2&gt;

&lt;p&gt;Finally, instruct the router to boot the newly installed OpenWrt firmware.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;hornet&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bootm 9f020000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The router will be accessible at &lt;a href="http://192.168.1.1"&gt;http://192.168.1.1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: You will need to reconfigure your computer's IP into this subnet before you will be able to access the router at this new address.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://openwrt.org/toh/tp-link/tl-mr3020"&gt;OpenWrt.org: TP-Link TL-MR3020 installation instructions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/sindhus/6351f9b6b5b57ba711f43fd1d3e27469"&gt;Unbrick|Debrick TP-LINK 3020 in OS X&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>tplink</category>
      <category>openwrt</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
