<?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>Forem: Michael Weibel</title>
    <description>The latest articles on Forem by Michael Weibel (@mweibel).</description>
    <link>https://forem.com/mweibel</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%2F172328%2F9343073d-899e-4be0-81c1-04aed9073ef4.jpeg</url>
      <title>Forem: Michael Weibel</title>
      <link>https://forem.com/mweibel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mweibel"/>
    <language>en</language>
    <item>
      <title>Deploying next.js on AWS ElasticBeanstalk</title>
      <dc:creator>Michael Weibel</dc:creator>
      <pubDate>Wed, 10 Jun 2020 06:04:43 +0000</pubDate>
      <link>https://forem.com/mweibel/deploying-next-js-on-aws-elasticbeanstalk-ab4</link>
      <guid>https://forem.com/mweibel/deploying-next-js-on-aws-elasticbeanstalk-ab4</guid>
      <description>&lt;p&gt;&lt;a href="https://aws.amazon.com/elasticbeanstalk/"&gt;AWS ElasticBeanstalk (EB)&lt;/a&gt; is a service to deploy applications in a simple manner. &lt;br&gt;
AWS EB has quite a range of features. It allows you to configure rolling deployment, monitoring, alerting, database setup, etc. It's generally much easier to use than doing it from scratch.&lt;/p&gt;

&lt;p&gt;As with all such systems, this comes at a cost: you initially don't know a lot about the system and figuring out what's wrong might be difficult. &lt;br&gt;
Additionally, AWS EB recently switched to &lt;a href="https://aws.amazon.com/amazon-linux-2/"&gt;Amazon Linux 2&lt;/a&gt;. This new version has a different way to deploy than the previous version "Amazon Linux AMI". As a result, lots of articles and StackOverflow questions/answers are outdated. &lt;br&gt;
The documentation on AWS itself could be a lot better, too. It's not always clear to which version the docs refer to. For example &lt;a href="https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environment-cfg-staticfiles.html"&gt;serving static files&lt;/a&gt; does not work for Amazon Linux 2.&lt;/p&gt;

&lt;p&gt;I deployed a &lt;a href="https://nextjs.org/"&gt;next.js&lt;/a&gt; app on AWS EB recently and learned a few tricks. Here's a quick summary of them.&lt;/p&gt;
&lt;h2&gt;
  
  
  NODE_ENV
&lt;/h2&gt;

&lt;p&gt;To configure the correct NODE_ENV when building and running the application on AWS EB, place the following contents in the folder &lt;code&gt;.ebextensions/options.config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;option_settings:
  aws:elasticbeanstalk:application:environment:
    NODE_ENV: production
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  .ebignore
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-configuration.html#eb-cli3-ebignore"&gt;&lt;code&gt;.ebignore&lt;/code&gt;&lt;/a&gt; allows to ignore files when deploying the repository archive using the EB CLI. The format is just like &lt;code&gt;.gitignore&lt;/code&gt; and if &lt;code&gt;.ebignore&lt;/code&gt; is not present, the deployment uses &lt;code&gt;.gitignore&lt;/code&gt; instead. Usually there are certain things which should be in git but not in the deployed archive, hence the need for a &lt;code&gt;.ebignore&lt;/code&gt; file. &lt;br&gt;
Here's my example &lt;code&gt;.ebignore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# dependencies
node_modules/

# repository/project stuff
.idea/
.git/
.gitlab-ci.yml
README.md

# misc
.DS_Store

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# non prod env files
.env.development
.env.test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  PORT env variable
&lt;/h2&gt;

&lt;p&gt;Like many other systems, AWS EB exposes the &lt;code&gt;PORT&lt;/code&gt; environment variable to specify on which port the app should listen on. If you don't &lt;a href="https://nextjs.org/docs/advanced-features/custom-server"&gt;customize the server&lt;/a&gt;, ensure to adjust your &lt;code&gt;npm start&lt;/code&gt; script in &lt;code&gt;package.json&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"start": "next start -p $PORT"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Using yarn instead of npm
&lt;/h2&gt;

&lt;p&gt;In case you have issues with dependencies not installed correctly (read: weird deployment issues you don't have locally), it might be because you use &lt;code&gt;yarn&lt;/code&gt; instead of &lt;code&gt;npm&lt;/code&gt;. AWS EB uses by default &lt;code&gt;npm&lt;/code&gt; to install your dependencies. If you use &lt;code&gt;yarn&lt;/code&gt;, the repository usually has a &lt;code&gt;yarn.lock&lt;/code&gt; file instead of a &lt;code&gt;package-lock.json&lt;/code&gt;. Here's how to "switch" to yarn instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# place in .platform/hooks/prebuild/yarn.sh

#!/bin/bash

# need to install node first to be able to install yarn (as at prebuild no node is present yet)
sudo curl --silent --location https://rpm.nodesource.com/setup_12.x | sudo bash -
sudo yum -y install nodejs

# install yarn
sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo
sudo yum -y install yarn

# install
cd /var/app/staging/

# debugging..
ls -lah

yarn install --prod

chown -R webapp:webapp node_modules/ || true # allow to fail
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ensure to specify the correct node.js version in the path of the &lt;code&gt;curl&lt;/code&gt; command. &lt;/p&gt;

&lt;p&gt;"switch" is in quotes because after predeploy &lt;code&gt;eb engine&lt;/code&gt; will still run &lt;code&gt;npm install&lt;/code&gt;. However it seems to work quite well regardless.&lt;br&gt;
I'd recommend: If you can avoid it, use npm.&lt;/p&gt;
&lt;h2&gt;
  
  
  Serving static files via nginx
&lt;/h2&gt;

&lt;p&gt;It makes sense to serve static files directly via nginx. This avoids unnecessary load on the node.js server and nginx is generally much faster in serving static content. &lt;br&gt;
Place the following file in &lt;code&gt;.platform/nginx/conf.d/elasticbeanstalk/static.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root /var/app/current/public;

location @backend {
  proxy_pass http://127.0.0.1:8080;
}

location /images/ {
  try_files $uri @backend;

  # perf optimisations
  sendfile           on;
  sendfile_max_chunk 1m;
  tcp_nopush         on;
  tcp_nodelay        on;
}
# add more folders as you need them, using as similar location directive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Additionally you could &lt;a href="https://steveholgado.com/nginx-for-nextjs/#caching-static-assets-with-nginx"&gt;add caching for the &lt;code&gt;/_next/static&lt;/code&gt; path - feel free to try it out&lt;/a&gt;. I didn't do it yet to avoid too many changes at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  GZIP compression
&lt;/h2&gt;

&lt;p&gt;Enabling GZIP Content-Encoding on nginx level requires you to override the default &lt;code&gt;nginx.conf&lt;/code&gt;. Find the default &lt;code&gt;nginx.conf&lt;/code&gt; in &lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt;, copy the contents to &lt;code&gt;.platform/nginx/nginx.conf&lt;/code&gt; and replace &lt;code&gt;gzip off;&lt;/code&gt; to &lt;code&gt;gzip on;&lt;/code&gt;.&lt;br&gt;
Here's the current (June 2020) example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#Elastic Beanstalk Nginx Configuration File

user                    nginx;
error_log               /var/log/nginx/error.log warn;
pid                     /var/run/nginx.pid;
worker_processes        auto;
worker_rlimit_nofile    32153;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    include       conf.d/*.conf;

    map $http_upgrade $connection_upgrade {
        default     "upgrade";
    }

    server {
        listen        80 default_server;
        access_log    /var/log/nginx/access.log main;

        client_header_timeout 60;
        client_body_timeout   60;
        keepalive_timeout     60;
        gzip                  on; # CHANGED(mw): enable gzip compression
        gzip_comp_level       4;
        gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

        # Include the Elastic Beanstalk generated locations
        include conf.d/elasticbeanstalk/*.conf;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, &lt;a href="https://nextjs.org/docs/api-reference/next.config.js/compression"&gt;disable &lt;code&gt;gzip&lt;/code&gt; compression in next.js&lt;/a&gt; to avoid double compressing and reduce load on the node.js server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;Run, in the following order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run build
$ eb deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Logging/Debugging
&lt;/h2&gt;

&lt;p&gt;Here's a bunch of important files/directories. You might need &lt;code&gt;sudo&lt;/code&gt; to see/read those paths.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Directory&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/etc/nginx/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nginx configurations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/var/app/current&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deployed application files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/var/app/staging&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only during deployment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/opt/elasticbeanstalk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Binaries, Configs, ... from AWS EB itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/var/proxy/staging&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nginx staging deployment config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/var/log/eb-engine.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deployment log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/var/log/web-stdout.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;App stdout log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/var/log/nginx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nginx log&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Other settings
&lt;/h2&gt;

&lt;p&gt;Ensure to configure your AWS EB setup in the web console as well. Setup &lt;a href="https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.rolling-version-deploy.html?icmpid=docs_elasticbeanstalk_console"&gt;rolling deployments&lt;/a&gt; and configure &lt;a href="https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-health.html"&gt;monitoring/alarms&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>aws</category>
      <category>elasticbeanstalk</category>
    </item>
    <item>
      <title>Add NVIDIA GPU support to k3s with containerd</title>
      <dc:creator>Michael Weibel</dc:creator>
      <pubDate>Fri, 13 Mar 2020 09:21:03 +0000</pubDate>
      <link>https://forem.com/mweibel/add-nvidia-gpu-support-to-k3s-with-containerd-4j17</link>
      <guid>https://forem.com/mweibel/add-nvidia-gpu-support-to-k3s-with-containerd-4j17</guid>
      <description>&lt;p&gt;After some failed attempts of adding GPU support to &lt;a href="https://k3s.io/"&gt;k3s&lt;/a&gt;, this article describes how to boot up a worker node with NVIDIA GPU support.&lt;br&gt;
k3s, for those who are new to it, is a very small &lt;a href="https://kubernetes.io/"&gt;kubernetes distribution&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are a few reasons why adding GPU support is not that easy. Main reason is that k3s is using &lt;a href="https://containerd.io/"&gt;containerd&lt;/a&gt; as it's container runtime. Most tutorials and also &lt;a href="https://github.com/NVIDIA/k8s-device-plugin"&gt;the official NVIDIA k8s device plugin&lt;/a&gt; assume docker as the container runtime. While you can easily switch to docker in k3s, we didn't want to change the runtime itself. &lt;br&gt;
&lt;a href="https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/"&gt;Kubernetes itself has a guide&lt;/a&gt; for adding GPU support which outlines the basic steps. &lt;/p&gt;

&lt;p&gt;The following recipe has been tested on GCP instances n2-standard-1 with a NVIDIA Tesla T4 GPU attached.&lt;br&gt;
It assumes a running master node. Each worker with an attached GPU needs a few additional steps which are outlined below. &lt;/p&gt;
&lt;h2&gt;
  
  
  Create device plugin DaemonSet
&lt;/h2&gt;

&lt;p&gt;The device plugin is responsible for advertising the &lt;code&gt;nvidia.com/gpu&lt;/code&gt; resource on a node (via kubelet).&lt;br&gt;
This needs to be done on the kubernetes node only once. Every node with the label &lt;code&gt;cloud.google.com/gke-accelerator&lt;/code&gt; then gets automatically a pod from this DaemonSet assigned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.14/cluster/addons/device-plugins/nvidia-gpu/daemonset.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The following steps are necessary for each node which needs GPU support. Placing it in a startup script is a good option. &lt;/p&gt;

&lt;h2&gt;
  
  
  Install drivers
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# required kernel module&lt;/span&gt;
modprobe ipmi_devintf

&lt;span class="c"&gt;# add necessary repositories&lt;/span&gt;
add-apt-repository &lt;span class="nt"&gt;-y&lt;/span&gt; ppa:graphics-drivers
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; https://nvidia.github.io/nvidia-container-runtime/gpgkey | &lt;span class="se"&gt;\&lt;/span&gt;
  apt-key add -
&lt;span class="nv"&gt;distribution&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$ID$VERSION_ID&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; https://nvidia.github.io/nvidia-container-runtime/&lt;span class="nv"&gt;$distribution&lt;/span&gt;/nvidia-container-runtime.list | &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;tee&lt;/span&gt; /etc/apt/sources.list.d/nvidia-container-runtime.list
apt-get update

&lt;span class="c"&gt;# install graphics driver&lt;/span&gt;
apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nvidia-driver-440 nvidia-container-runtime nvidia-modprobe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Ensure nvidia driver is loaded and device files ready
&lt;/h2&gt;

&lt;p&gt;From: &lt;a href="https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#runfile-verifications"&gt;https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#runfile-verifications&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;/sbin/modprobe nvidia

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="c"&gt;# Count the number of NVIDIA controllers found.&lt;/span&gt;
  &lt;span class="nv"&gt;NVDEVS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;lspci | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; NVIDIA&lt;span class="sb"&gt;`&lt;/span&gt;
  &lt;span class="nv"&gt;N3D&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NVDEVS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"3D controller"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
  &lt;span class="nv"&gt;NVGA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NVDEVS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"VGA compatible controller"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;

  &lt;span class="nv"&gt;N&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;expr&lt;/span&gt; &lt;span class="nv"&gt;$N3D&lt;/span&gt; + &lt;span class="nv"&gt;$NVGA&lt;/span&gt; - 1&lt;span class="sb"&gt;`&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;0 &lt;span class="nv"&gt;$N&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;mknod&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 666 /dev/nvidia&lt;span class="nv"&gt;$i&lt;/span&gt; c 195 &lt;span class="nv"&gt;$i&lt;/span&gt;
  &lt;span class="k"&gt;done

  &lt;/span&gt;&lt;span class="nb"&gt;mknod&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 666 /dev/nvidiactl c 195 255

&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

/sbin/modprobe nvidia-uvm

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="c"&gt;# Find out the major device number used by the nvidia-uvm driver&lt;/span&gt;
  &lt;span class="nv"&gt;D&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;grep &lt;/span&gt;nvidia-uvm /proc/devices | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $1}'&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;

  &lt;span class="nb"&gt;mknod&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 666 /dev/nvidia-uvm c &lt;span class="nv"&gt;$D&lt;/span&gt; 0
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Install k3s
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sfL&lt;/span&gt; https://get.k3s.io | &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;INSTALL_K3S_SKIP_START&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;K3S_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://IP_OF_MASTER_ADDRESS:6443 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;K3S_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;CONTENT_OF_/var/lib/rancher/k3s/server/node-token_ON_MASTER &lt;span class="se"&gt;\&lt;/span&gt;
    sh &lt;span class="nt"&gt;-s&lt;/span&gt; - &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--node-label&lt;/span&gt; &lt;span class="s2"&gt;"cloud.google.com/gke-accelerator=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fs&lt;/span&gt; &lt;span class="s2"&gt;"http://metadata.google.internal/computeMetadata/v1/instance/attributes/gpu-platform"&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Metadata-Flavor: Google"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;INSTALL_K3S_SKIP_START&lt;/code&gt; prevents k3s from starting, as we need first to change containerd config (see below)&lt;br&gt;
&lt;code&gt;node-label&lt;/code&gt; should be set to that key, the value is only important if you want to schedule pods based on the GPU available. The example here uses a metadata attribute on the instance within GCE. Feel free to change that to something else or just &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Configure containerd
&lt;/h2&gt;

&lt;p&gt;Containerd needs to be changed to use a different container runtime. This can be achieved by adjusting the &lt;a href="https://rancher.com/docs/k3s/latest/en/advanced/#using-docker-as-the-container-runtime"&gt;&lt;code&gt;config.toml&lt;/code&gt; or rather creating a &lt;code&gt;config.toml.tmpl&lt;/code&gt; file&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/lib/rancher/k3s/agent/etc/containerd/

&lt;span class="c"&gt;# why "EOF":&lt;/span&gt;
&lt;span class="c"&gt;# https://serverfault.com/questions/399428/how-do-you-escape-characters-in-heredoc&lt;/span&gt;
&lt;span class="c"&gt;# ($ signs would need to be escaped -&amp;gt; use "EOF" instead of EOF)&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;" &amp;gt; /var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl
[plugins.opt]
  path = "{{ .NodeConfig.Containerd.Opt }}"

[plugins.cri]
  stream_server_address = "127.0.0.1"
  stream_server_port = "10010"

{{- if .IsRunningInUserNS }}
  disable_cgroup = true
  disable_apparmor = true
  restrict_oom_score_adj = true
{{end}}

{{- if .NodeConfig.AgentConfig.PauseImage }}
  sandbox_image = "{{ .NodeConfig.AgentConfig.PauseImage }}"
{{end}}

{{- if not .NodeConfig.NoFlannel }}
[plugins.cri.cni]
  bin_dir = "{{ .NodeConfig.AgentConfig.CNIBinDir }}"
  conf_dir = "{{ .NodeConfig.AgentConfig.CNIConfDir }}"
{{end}}

[plugins.cri.containerd.runtimes.runc]
  # ---- changed from 'io.containerd.runc.v2' for GPU support
  runtime_type = "io.containerd.runtime.v1.linux"

# ---- added for GPU support
[plugins.linux]
  runtime = "nvidia-container-runtime"

{{ if .PrivateRegistryConfig }}
{{ if .PrivateRegistryConfig.Mirrors }}
[plugins.cri.registry.mirrors]{{end}}
{{range &lt;/span&gt;&lt;span class="nv"&gt;$k&lt;/span&gt;&lt;span class="sh"&gt;, &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt; := .PrivateRegistryConfig.Mirrors }}
[plugins.cri.registry.mirrors."{{&lt;/span&gt;&lt;span class="nv"&gt;$k&lt;/span&gt;&lt;span class="sh"&gt;}}"]
  endpoint = [{{range &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="sh"&gt;, &lt;/span&gt;&lt;span class="nv"&gt;$j&lt;/span&gt;&lt;span class="sh"&gt; := &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.Endpoints}}{{if &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="sh"&gt;}}, {{end}}{{printf "%q" .}}{{end}}]
{{end}}

{{range &lt;/span&gt;&lt;span class="nv"&gt;$k&lt;/span&gt;&lt;span class="sh"&gt;, &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt; := .PrivateRegistryConfig.Configs }}
{{ if &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.Auth }}
[plugins.cri.registry.configs."{{&lt;/span&gt;&lt;span class="nv"&gt;$k&lt;/span&gt;&lt;span class="sh"&gt;}}".auth]
  {{ if &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.Auth.Username }}username = "{{ &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.Auth.Username }}"{{end}}
  {{ if &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.Auth.Password }}password = "{{ &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.Auth.Password }}"{{end}}
  {{ if &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.Auth.Auth }}auth = "{{ &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.Auth.Auth }}"{{end}}
  {{ if &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.Auth.IdentityToken }}identitytoken = "{{ &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.Auth.IdentityToken }}"{{end}}
{{end}}
{{ if &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.TLS }}
[plugins.cri.registry.configs."{{&lt;/span&gt;&lt;span class="nv"&gt;$k&lt;/span&gt;&lt;span class="sh"&gt;}}".tls]
  {{ if &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.TLS.CAFile }}ca_file = "{{ &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.TLS.CAFile }}"{{end}}
  {{ if &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.TLS.CertFile }}cert_file = "{{ &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.TLS.CertFile }}"{{end}}
  {{ if &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.TLS.KeyFile }}key_file = "{{ &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="sh"&gt;.TLS.KeyFile }}"{{end}}
{{end}}
{{end}}
{{end}}
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Start k3s agent
&lt;/h2&gt;

&lt;p&gt;Start k3s: &lt;code&gt;systemctl start k3s-agent&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's it! :) &lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>k3s</category>
      <category>gpu</category>
      <category>containerd</category>
    </item>
  </channel>
</rss>
