k3s-install.sh 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  1. #!/bin/sh
  2. set -e
  3. set -o noglob
  4. # Usage:
  5. # curl ... | ENV_VAR=... sh -
  6. # or
  7. # ENV_VAR=... ./install.sh
  8. #
  9. # Example:
  10. # Installing a server without traefik:
  11. # curl ... | INSTALL_K3S_EXEC="--disable=traefik" sh -
  12. # Installing an agent to point at a server:
  13. # curl ... | K3S_TOKEN=xxx K3S_URL=https://server-url:6443 sh -
  14. #
  15. # Environment variables:
  16. # - K3S_*
  17. # Environment variables which begin with K3S_ will be preserved for the
  18. # systemd service to use. Setting K3S_URL without explicitly setting
  19. # a systemd exec command will default the command to "agent", and we
  20. # enforce that K3S_TOKEN is also set.
  21. #
  22. # - INSTALL_K3S_SKIP_DOWNLOAD
  23. # If set to true will not download k3s hash or binary.
  24. #
  25. # - INSTALL_K3S_FORCE_RESTART
  26. # If set to true will always restart the K3s service
  27. #
  28. # - INSTALL_K3S_SYMLINK
  29. # If set to 'skip' will not create symlinks, 'force' will overwrite,
  30. # default will symlink if command does not exist in path.
  31. #
  32. # - INSTALL_K3S_SKIP_ENABLE
  33. # If set to true will not enable or start k3s service.
  34. #
  35. # - INSTALL_K3S_SKIP_START
  36. # If set to true will not start k3s service.
  37. #
  38. # - INSTALL_K3S_VERSION
  39. # Version of k3s to download from github. Will attempt to download from the
  40. # stable channel if not specified.
  41. #
  42. # - INSTALL_K3S_COMMIT
  43. # Commit of k3s to download from temporary cloud storage.
  44. # * (for developer & QA use)
  45. #
  46. # - INSTALL_K3S_BIN_DIR
  47. # Directory to install k3s binary, links, and uninstall script to, or use
  48. # /usr/local/bin as the default
  49. #
  50. # - INSTALL_K3S_BIN_DIR_READ_ONLY
  51. # If set to true will not write files to INSTALL_K3S_BIN_DIR, forces
  52. # setting INSTALL_K3S_SKIP_DOWNLOAD=true
  53. #
  54. # - INSTALL_K3S_SYSTEMD_DIR
  55. # Directory to install systemd service and environment files to, or use
  56. # /etc/systemd/system as the default
  57. #
  58. # - INSTALL_K3S_EXEC or script arguments
  59. # Command with flags to use for launching k3s in the systemd service, if
  60. # the command is not specified will default to "agent" if K3S_URL is set
  61. # or "server" if not. The final systemd command resolves to a combination
  62. # of EXEC and script args ($@).
  63. #
  64. # The following commands result in the same behavior:
  65. # curl ... | INSTALL_K3S_EXEC="--disable=traefik" sh -s -
  66. # curl ... | INSTALL_K3S_EXEC="server --disable=traefik" sh -s -
  67. # curl ... | INSTALL_K3S_EXEC="server" sh -s - --disable=traefik
  68. # curl ... | sh -s - server --disable=traefik
  69. # curl ... | sh -s - --disable=traefik
  70. #
  71. # - INSTALL_K3S_NAME
  72. # Name of systemd service to create, will default from the k3s exec command
  73. # if not specified. If specified the name will be prefixed with 'k3s-'.
  74. #
  75. # - INSTALL_K3S_TYPE
  76. # Type of systemd service to create, will default from the k3s exec command
  77. # if not specified.
  78. #
  79. # - INSTALL_K3S_SELINUX_WARN
  80. # If set to true will continue if k3s-selinux policy is not found.
  81. #
  82. # - INSTALL_K3S_SKIP_SELINUX_RPM
  83. # If set to true will skip automatic installation of the k3s RPM.
  84. #
  85. # - INSTALL_K3S_CHANNEL_URL
  86. # Channel URL for fetching k3s download URL.
  87. # Defaults to 'https://update.k3s.io/v1-release/channels'.
  88. #
  89. # - INSTALL_K3S_CHANNEL
  90. # Channel to use for fetching k3s download URL.
  91. # Defaults to 'stable'.
  92. GITHUB_URL=https://github.com/k3s-io/k3s/releases
  93. STORAGE_URL=https://k3s-ci-builds.s3.amazonaws.com
  94. DOWNLOADER=
  95. # --- helper functions for logs ---
  96. info()
  97. {
  98. echo '[INFO] ' "$@"
  99. }
  100. warn()
  101. {
  102. echo '[WARN] ' "$@" >&2
  103. }
  104. fatal()
  105. {
  106. echo '[ERROR] ' "$@" >&2
  107. exit 1
  108. }
  109. # --- fatal if no systemd or openrc ---
  110. verify_system() {
  111. if [ -x /sbin/openrc-run ]; then
  112. HAS_OPENRC=true
  113. return
  114. fi
  115. if [ -x /bin/systemctl ] || type systemctl > /dev/null 2>&1; then
  116. HAS_SYSTEMD=true
  117. return
  118. fi
  119. fatal 'Can not find systemd or openrc to use as a process supervisor for k3s'
  120. }
  121. # --- add quotes to command arguments ---
  122. quote() {
  123. for arg in "$@"; do
  124. printf '%s\n' "$arg" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/"
  125. done
  126. }
  127. # --- add indentation and trailing slash to quoted args ---
  128. quote_indent() {
  129. printf ' \\\n'
  130. for arg in "$@"; do
  131. printf '\t%s \\\n' "$(quote "$arg")"
  132. done
  133. }
  134. # --- escape most punctuation characters, except quotes, forward slash, and space ---
  135. escape() {
  136. printf '%s' "$@" | sed -e 's/\([][!#$%&()*;<=>?\_`{|}]\)/\\\1/g;'
  137. }
  138. # --- escape double quotes ---
  139. escape_dq() {
  140. printf '%s' "$@" | sed -e 's/"/\\"/g'
  141. }
  142. # --- ensures $K3S_URL is empty or begins with https://, exiting fatally otherwise ---
  143. verify_k3s_url() {
  144. case "${K3S_URL}" in
  145. "")
  146. ;;
  147. https://*)
  148. ;;
  149. *)
  150. fatal "Only https:// URLs are supported for K3S_URL (have ${K3S_URL})"
  151. ;;
  152. esac
  153. }
  154. # --- define needed environment variables ---
  155. setup_env() {
  156. # --- use command args if passed or create default ---
  157. case "$1" in
  158. # --- if we only have flags discover if command should be server or agent ---
  159. (-*|"")
  160. if [ -z "${K3S_URL}" ]; then
  161. CMD_K3S=server
  162. else
  163. if [ -z "${K3S_TOKEN}" ] && [ -z "${K3S_TOKEN_FILE}" ]; then
  164. fatal "Defaulted k3s exec command to 'agent' because K3S_URL is defined, but K3S_TOKEN or K3S_TOKEN_FILE is not defined."
  165. fi
  166. CMD_K3S=agent
  167. fi
  168. ;;
  169. # --- command is provided ---
  170. (*)
  171. CMD_K3S=$1
  172. shift
  173. ;;
  174. esac
  175. verify_k3s_url
  176. CMD_K3S_EXEC="${CMD_K3S}$(quote_indent "$@")"
  177. # --- use systemd name if defined or create default ---
  178. if [ -n "${INSTALL_K3S_NAME}" ]; then
  179. SYSTEM_NAME=k3s-${INSTALL_K3S_NAME}
  180. else
  181. if [ "${CMD_K3S}" = server ]; then
  182. SYSTEM_NAME=k3s
  183. else
  184. SYSTEM_NAME=k3s-${CMD_K3S}
  185. fi
  186. fi
  187. # --- check for invalid characters in system name ---
  188. valid_chars=$(printf '%s' "${SYSTEM_NAME}" | sed -e 's/[][!#$%&()*;<=>?\_`{|}/[:space:]]/^/g;' )
  189. if [ "${SYSTEM_NAME}" != "${valid_chars}" ]; then
  190. invalid_chars=$(printf '%s' "${valid_chars}" | sed -e 's/[^^]/ /g')
  191. fatal "Invalid characters for system name:
  192. ${SYSTEM_NAME}
  193. ${invalid_chars}"
  194. fi
  195. # --- use sudo if we are not already root ---
  196. SUDO=sudo
  197. if [ $(id -u) -eq 0 ]; then
  198. SUDO=
  199. fi
  200. # --- use systemd type if defined or create default ---
  201. if [ -n "${INSTALL_K3S_TYPE}" ]; then
  202. SYSTEMD_TYPE=${INSTALL_K3S_TYPE}
  203. else
  204. SYSTEMD_TYPE=notify
  205. fi
  206. # --- use binary install directory if defined or create default ---
  207. if [ -n "${INSTALL_K3S_BIN_DIR}" ]; then
  208. BIN_DIR=${INSTALL_K3S_BIN_DIR}
  209. else
  210. # --- use /usr/local/bin if root can write to it, otherwise use /opt/bin if it exists
  211. BIN_DIR=/usr/local/bin
  212. if ! $SUDO sh -c "touch ${BIN_DIR}/k3s-ro-test && rm -rf ${BIN_DIR}/k3s-ro-test"; then
  213. if [ -d /opt/bin ]; then
  214. BIN_DIR=/opt/bin
  215. fi
  216. fi
  217. fi
  218. # --- use systemd directory if defined or create default ---
  219. if [ -n "${INSTALL_K3S_SYSTEMD_DIR}" ]; then
  220. SYSTEMD_DIR="${INSTALL_K3S_SYSTEMD_DIR}"
  221. else
  222. SYSTEMD_DIR=/etc/systemd/system
  223. fi
  224. # --- set related files from system name ---
  225. SERVICE_K3S=${SYSTEM_NAME}.service
  226. UNINSTALL_K3S_SH=${UNINSTALL_K3S_SH:-${BIN_DIR}/${SYSTEM_NAME}-uninstall.sh}
  227. KILLALL_K3S_SH=${KILLALL_K3S_SH:-${BIN_DIR}/k3s-killall.sh}
  228. # --- use service or environment location depending on systemd/openrc ---
  229. if [ "${HAS_SYSTEMD}" = true ]; then
  230. FILE_K3S_SERVICE=${SYSTEMD_DIR}/${SERVICE_K3S}
  231. FILE_K3S_ENV=${SYSTEMD_DIR}/${SERVICE_K3S}.env
  232. elif [ "${HAS_OPENRC}" = true ]; then
  233. $SUDO mkdir -p /etc/rancher/k3s
  234. FILE_K3S_SERVICE=/etc/init.d/${SYSTEM_NAME}
  235. FILE_K3S_ENV=/etc/rancher/k3s/${SYSTEM_NAME}.env
  236. fi
  237. # --- get hash of config & exec for currently installed k3s ---
  238. PRE_INSTALL_HASHES=$(get_installed_hashes)
  239. # --- if bin directory is read only skip download ---
  240. if [ "${INSTALL_K3S_BIN_DIR_READ_ONLY}" = true ]; then
  241. INSTALL_K3S_SKIP_DOWNLOAD=true
  242. fi
  243. # --- setup channel values
  244. INSTALL_K3S_CHANNEL_URL=${INSTALL_K3S_CHANNEL_URL:-'https://update.k3s.io/v1-release/channels'}
  245. INSTALL_K3S_CHANNEL=${INSTALL_K3S_CHANNEL:-'stable'}
  246. }
  247. # --- check if skip download environment variable set ---
  248. can_skip_download_binary() {
  249. if [ "${INSTALL_K3S_SKIP_DOWNLOAD}" != true ] && [ "${INSTALL_K3S_SKIP_DOWNLOAD}" != binary ]; then
  250. return 1
  251. fi
  252. }
  253. can_skip_download_selinux() {
  254. if [ "${INSTALL_K3S_SKIP_DOWNLOAD}" != true ] && [ "${INSTALL_K3S_SKIP_DOWNLOAD}" != selinux ]; then
  255. return 1
  256. fi
  257. }
  258. # --- verify an executable k3s binary is installed ---
  259. verify_k3s_is_executable() {
  260. if [ ! -x ${BIN_DIR}/k3s ]; then
  261. fatal "Executable k3s binary not found at ${BIN_DIR}/k3s"
  262. fi
  263. }
  264. # --- set arch and suffix, fatal if architecture not supported ---
  265. setup_verify_arch() {
  266. if [ -z "$ARCH" ]; then
  267. ARCH=$(uname -m)
  268. fi
  269. case $ARCH in
  270. amd64)
  271. ARCH=amd64
  272. SUFFIX=
  273. ;;
  274. x86_64)
  275. ARCH=amd64
  276. SUFFIX=
  277. ;;
  278. arm64)
  279. ARCH=arm64
  280. SUFFIX=-${ARCH}
  281. ;;
  282. s390x)
  283. ARCH=s390x
  284. SUFFIX=-${ARCH}
  285. ;;
  286. aarch64)
  287. ARCH=arm64
  288. SUFFIX=-${ARCH}
  289. ;;
  290. arm*)
  291. ARCH=arm
  292. SUFFIX=-${ARCH}hf
  293. ;;
  294. *)
  295. fatal "Unsupported architecture $ARCH"
  296. esac
  297. }
  298. # --- verify existence of network downloader executable ---
  299. verify_downloader() {
  300. # Return failure if it doesn't exist or is no executable
  301. [ -x "$(command -v $1)" ] || return 1
  302. # Set verified executable as our downloader program and return success
  303. DOWNLOADER=$1
  304. return 0
  305. }
  306. # --- create temporary directory and cleanup when done ---
  307. setup_tmp() {
  308. TMP_DIR=$(mktemp -d -t k3s-install.XXXXXXXXXX)
  309. TMP_HASH=${TMP_DIR}/k3s.hash
  310. TMP_BIN=${TMP_DIR}/k3s.bin
  311. cleanup() {
  312. code=$?
  313. set +e
  314. trap - EXIT
  315. rm -rf ${TMP_DIR}
  316. exit $code
  317. }
  318. trap cleanup INT EXIT
  319. }
  320. # --- use desired k3s version if defined or find version from channel ---
  321. get_release_version() {
  322. if [ -n "${INSTALL_K3S_COMMIT}" ]; then
  323. VERSION_K3S="commit ${INSTALL_K3S_COMMIT}"
  324. elif [ -n "${INSTALL_K3S_VERSION}" ]; then
  325. VERSION_K3S=${INSTALL_K3S_VERSION}
  326. else
  327. info "Finding release for channel ${INSTALL_K3S_CHANNEL}"
  328. version_url="${INSTALL_K3S_CHANNEL_URL}/${INSTALL_K3S_CHANNEL}"
  329. case $DOWNLOADER in
  330. curl)
  331. VERSION_K3S=$(curl -w '%{url_effective}' -L -s -S ${version_url} -o /dev/null | sed -e 's|.*/||')
  332. ;;
  333. wget)
  334. VERSION_K3S=$(wget -SqO /dev/null ${version_url} 2>&1 | grep -i Location | sed -e 's|.*/||')
  335. ;;
  336. *)
  337. fatal "Incorrect downloader executable '$DOWNLOADER'"
  338. ;;
  339. esac
  340. fi
  341. info "Using ${VERSION_K3S} as release"
  342. }
  343. # --- get k3s-selinux version ---
  344. get_k3s_selinux_version() {
  345. available_version="k3s-selinux-1.2-2.${rpm_target}.noarch.rpm"
  346. info "Finding available k3s-selinux versions"
  347. # run verify_downloader in case it binary installation was skipped
  348. verify_downloader curl || verify_downloader wget || fatal 'Can not find curl or wget for downloading files'
  349. case $DOWNLOADER in
  350. curl)
  351. DOWNLOADER_OPTS="-s"
  352. ;;
  353. wget)
  354. DOWNLOADER_OPTS="-q -O -"
  355. ;;
  356. *)
  357. fatal "Incorrect downloader executable '$DOWNLOADER'"
  358. ;;
  359. esac
  360. for i in {1..3}; do
  361. set +e
  362. if [ "${rpm_channel}" = "testing" ]; then
  363. version=$(timeout 5 ${DOWNLOADER} ${DOWNLOADER_OPTS} https://api.github.com/repos/k3s-io/k3s-selinux/releases | grep browser_download_url | awk '{ print $2 }' | grep -oE "[^\/]+${rpm_target}\.noarch\.rpm" | head -n 1)
  364. else
  365. version=$(timeout 5 ${DOWNLOADER} ${DOWNLOADER_OPTS} https://api.github.com/repos/k3s-io/k3s-selinux/releases/latest | grep browser_download_url | awk '{ print $2 }' | grep -oE "[^\/]+${rpm_target}\.noarch\.rpm")
  366. fi
  367. set -e
  368. if [ "${version}" != "" ]; then
  369. break
  370. fi
  371. sleep 1
  372. done
  373. if [ "${version}" == "" ]; then
  374. warn "Failed to get available versions of k3s-selinux..defaulting to ${available_version}"
  375. return
  376. fi
  377. available_version=${version}
  378. }
  379. # --- download from github url ---
  380. download() {
  381. [ $# -eq 2 ] || fatal 'download needs exactly 2 arguments'
  382. set +e
  383. case $DOWNLOADER in
  384. curl)
  385. curl -o $1 -sfL $2
  386. ;;
  387. wget)
  388. wget -qO $1 $2
  389. ;;
  390. *)
  391. fatal "Incorrect executable '$DOWNLOADER'"
  392. ;;
  393. esac
  394. # Abort if download command failed
  395. [ $? -eq 0 ] || fatal 'Download failed'
  396. set -e
  397. }
  398. # --- download hash from github url ---
  399. download_hash() {
  400. if [ -n "${INSTALL_K3S_COMMIT}" ]; then
  401. HASH_URL=${STORAGE_URL}/k3s${SUFFIX}-${INSTALL_K3S_COMMIT}.sha256sum
  402. else
  403. HASH_URL=${GITHUB_URL}/download/${VERSION_K3S}/sha256sum-${ARCH}.txt
  404. fi
  405. info "Downloading hash ${HASH_URL}"
  406. download ${TMP_HASH} ${HASH_URL}
  407. HASH_EXPECTED=$(grep " k3s${SUFFIX}$" ${TMP_HASH})
  408. HASH_EXPECTED=${HASH_EXPECTED%%[[:blank:]]*}
  409. }
  410. # --- check hash against installed version ---
  411. installed_hash_matches() {
  412. if [ -x ${BIN_DIR}/k3s ]; then
  413. HASH_INSTALLED=$(sha256sum ${BIN_DIR}/k3s)
  414. HASH_INSTALLED=${HASH_INSTALLED%%[[:blank:]]*}
  415. if [ "${HASH_EXPECTED}" = "${HASH_INSTALLED}" ]; then
  416. return
  417. fi
  418. fi
  419. return 1
  420. }
  421. # --- download binary from github url ---
  422. download_binary() {
  423. if [ -n "${INSTALL_K3S_COMMIT}" ]; then
  424. BIN_URL=${STORAGE_URL}/k3s${SUFFIX}-${INSTALL_K3S_COMMIT}
  425. else
  426. BIN_URL=${GITHUB_URL}/download/${VERSION_K3S}/k3s${SUFFIX}
  427. fi
  428. info "Downloading binary ${BIN_URL}"
  429. download ${TMP_BIN} ${BIN_URL}
  430. }
  431. # --- verify downloaded binary hash ---
  432. verify_binary() {
  433. info "Verifying binary download"
  434. HASH_BIN=$(sha256sum ${TMP_BIN})
  435. HASH_BIN=${HASH_BIN%%[[:blank:]]*}
  436. if [ "${HASH_EXPECTED}" != "${HASH_BIN}" ]; then
  437. fatal "Download sha256 does not match ${HASH_EXPECTED}, got ${HASH_BIN}"
  438. fi
  439. }
  440. # --- setup permissions and move binary to system directory ---
  441. setup_binary() {
  442. chmod 755 ${TMP_BIN}
  443. info "Installing k3s to ${BIN_DIR}/k3s"
  444. $SUDO chown root:root ${TMP_BIN}
  445. $SUDO mv -f ${TMP_BIN} ${BIN_DIR}/k3s
  446. }
  447. # --- setup selinux policy ---
  448. setup_selinux() {
  449. case ${INSTALL_K3S_CHANNEL} in
  450. *testing)
  451. rpm_channel=testing
  452. ;;
  453. *latest)
  454. rpm_channel=latest
  455. ;;
  456. *)
  457. rpm_channel=stable
  458. ;;
  459. esac
  460. rpm_site="rpm.rancher.io"
  461. if [ "${rpm_channel}" = "testing" ]; then
  462. rpm_site="rpm-testing.rancher.io"
  463. fi
  464. [ -r /etc/os-release ] && . /etc/os-release
  465. if [ `expr "${ID_LIKE}" : ".*suse.*"` != 0 ]; then
  466. rpm_target=sle
  467. rpm_site_infix=microos
  468. package_installer=zypper
  469. if [ "${ID_LIKE:-}" = suse ] && ( [ "${VARIANT_ID:-}" = sle-micro ] || [ "${ID:-}" = sle-micro ] ); then
  470. rpm_target=sle
  471. rpm_site_infix=slemicro
  472. package_installer=zypper
  473. fi
  474. elif [ "${ID_LIKE:-}" = coreos ] || [ "${VARIANT_ID:-}" = coreos ]; then
  475. rpm_target=coreos
  476. rpm_site_infix=coreos
  477. package_installer=rpm-ostree
  478. elif [ "${VERSION_ID%%.*}" = "7" ]; then
  479. rpm_target=el7
  480. rpm_site_infix=centos/7
  481. package_installer=yum
  482. elif [ "${VERSION_ID%%.*}" = "8" ] || [ "${VERSION_ID%%.*}" -gt "36" ]; then
  483. rpm_target=el8
  484. rpm_site_infix=centos/8
  485. package_installer=yum
  486. else
  487. rpm_target=el9
  488. rpm_site_infix=centos/9
  489. package_installer=yum
  490. fi
  491. if [ "${package_installer}" = "rpm-ostree" ] && [ -x /bin/yum ]; then
  492. package_installer=yum
  493. fi
  494. if [ "${package_installer}" = "yum" ] && [ -x /usr/bin/dnf ]; then
  495. package_installer=dnf
  496. fi
  497. policy_hint="please install:
  498. ${package_installer} install -y container-selinux
  499. ${package_installer} install -y https://${rpm_site}/k3s/${rpm_channel}/common/${rpm_site_infix}/noarch/${available_version}
  500. "
  501. if [ "$INSTALL_K3S_SKIP_SELINUX_RPM" = true ] || can_skip_download_selinux || [ ! -d /usr/share/selinux ]; then
  502. info "Skipping installation of SELinux RPM"
  503. return
  504. fi
  505. get_k3s_selinux_version
  506. install_selinux_rpm ${rpm_site} ${rpm_channel} ${rpm_target} ${rpm_site_infix}
  507. policy_error=fatal
  508. if [ "$INSTALL_K3S_SELINUX_WARN" = true ] || [ "${ID_LIKE:-}" = coreos ] || [ "${VARIANT_ID:-}" = coreos ]; then
  509. policy_error=warn
  510. fi
  511. if ! $SUDO chcon -u system_u -r object_r -t container_runtime_exec_t ${BIN_DIR}/k3s >/dev/null 2>&1; then
  512. if $SUDO grep '^\s*SELINUX=enforcing' /etc/selinux/config >/dev/null 2>&1; then
  513. $policy_error "Failed to apply container_runtime_exec_t to ${BIN_DIR}/k3s, ${policy_hint}"
  514. fi
  515. elif [ ! -f /usr/share/selinux/packages/k3s.pp ]; then
  516. if [ -x /usr/sbin/transactional-update ] || [ "${ID_LIKE:-}" = coreos ] || [ "${VARIANT_ID:-}" = coreos ]; then
  517. warn "Please reboot your machine to activate the changes and avoid data loss."
  518. else
  519. $policy_error "Failed to find the k3s-selinux policy, ${policy_hint}"
  520. fi
  521. fi
  522. }
  523. install_selinux_rpm() {
  524. if [ -r /etc/redhat-release ] || [ -r /etc/centos-release ] || [ -r /etc/oracle-release ] || [ -r /etc/fedora-release ] || [ "${ID_LIKE%%[ ]*}" = "suse" ]; then
  525. repodir=/etc/yum.repos.d
  526. if [ -d /etc/zypp/repos.d ]; then
  527. repodir=/etc/zypp/repos.d
  528. fi
  529. set +o noglob
  530. $SUDO rm -f ${repodir}/rancher-k3s-common*.repo
  531. set -o noglob
  532. if [ -r /etc/redhat-release ] && [ "${3}" = "el7" ]; then
  533. $SUDO yum install -y yum-utils
  534. $SUDO yum-config-manager --enable rhel-7-server-extras-rpms
  535. fi
  536. $SUDO tee ${repodir}/rancher-k3s-common.repo >/dev/null << EOF
  537. [rancher-k3s-common-${2}]
  538. name=Rancher K3s Common (${2})
  539. baseurl=https://${1}/k3s/${2}/common/${4}/noarch
  540. enabled=1
  541. gpgcheck=1
  542. repo_gpgcheck=0
  543. gpgkey=https://${1}/public.key
  544. EOF
  545. case ${3} in
  546. sle)
  547. rpm_installer="zypper --gpg-auto-import-keys"
  548. if [ "${TRANSACTIONAL_UPDATE=false}" != "true" ] && [ -x /usr/sbin/transactional-update ]; then
  549. transactional_update_run="transactional-update --no-selfupdate -d run"
  550. rpm_installer="transactional-update --no-selfupdate -d run ${rpm_installer}"
  551. : "${INSTALL_K3S_SKIP_START:=true}"
  552. fi
  553. # create the /var/lib/rpm-state in SLE systems to fix the prein selinux macro
  554. ${transactional_update_run} mkdir -p /var/lib/rpm-state
  555. ;;
  556. coreos)
  557. rpm_installer="rpm-ostree --idempotent"
  558. # rpm_install_extra_args="--apply-live"
  559. : "${INSTALL_K3S_SKIP_START:=true}"
  560. ;;
  561. *)
  562. rpm_installer="yum"
  563. ;;
  564. esac
  565. if [ "${rpm_installer}" = "yum" ] && [ -x /usr/bin/dnf ]; then
  566. rpm_installer=dnf
  567. fi
  568. if rpm -q --quiet k3s-selinux; then
  569. # remove k3s-selinux module before upgrade to allow container-selinux to upgrade safely
  570. if check_available_upgrades container-selinux ${3} && check_available_upgrades k3s-selinux ${3}; then
  571. MODULE_PRIORITY=$($SUDO semodule --list=full | grep k3s | cut -f1 -d" ")
  572. if [ -n "${MODULE_PRIORITY}" ]; then
  573. $SUDO semodule -X $MODULE_PRIORITY -r k3s || true
  574. fi
  575. fi
  576. fi
  577. # shellcheck disable=SC2086
  578. $SUDO ${rpm_installer} install -y "k3s-selinux"
  579. fi
  580. return
  581. }
  582. check_available_upgrades() {
  583. set +e
  584. case ${2} in
  585. sle)
  586. available_upgrades=$($SUDO zypper -q -t -s 11 se -s -u --type package $1 | tail -n 1 | grep -v "No matching" | awk '{print $3}')
  587. ;;
  588. coreos)
  589. # currently rpm-ostree does not support search functionality https://github.com/coreos/rpm-ostree/issues/1877
  590. ;;
  591. *)
  592. available_upgrades=$($SUDO yum -q --refresh list $1 --upgrades | tail -n 1 | awk '{print $2}')
  593. ;;
  594. esac
  595. set -e
  596. if [ -n "${available_upgrades}" ]; then
  597. return 0
  598. fi
  599. return 1
  600. }
  601. # --- download and verify k3s ---
  602. download_and_verify() {
  603. if can_skip_download_binary; then
  604. info 'Skipping k3s download and verify'
  605. verify_k3s_is_executable
  606. return
  607. fi
  608. setup_verify_arch
  609. verify_downloader curl || verify_downloader wget || fatal 'Can not find curl or wget for downloading files'
  610. setup_tmp
  611. get_release_version
  612. download_hash
  613. if installed_hash_matches; then
  614. info 'Skipping binary downloaded, installed k3s matches hash'
  615. return
  616. fi
  617. download_binary
  618. verify_binary
  619. setup_binary
  620. }
  621. # --- add additional utility links ---
  622. create_symlinks() {
  623. [ "${INSTALL_K3S_BIN_DIR_READ_ONLY}" = true ] && return
  624. [ "${INSTALL_K3S_SYMLINK}" = skip ] && return
  625. for cmd in kubectl crictl ctr; do
  626. if [ ! -e ${BIN_DIR}/${cmd} ] || [ "${INSTALL_K3S_SYMLINK}" = force ]; then
  627. which_cmd=$(command -v ${cmd} 2>/dev/null || true)
  628. if [ -z "${which_cmd}" ] || [ "${INSTALL_K3S_SYMLINK}" = force ]; then
  629. info "Creating ${BIN_DIR}/${cmd} symlink to k3s"
  630. $SUDO ln -sf k3s ${BIN_DIR}/${cmd}
  631. else
  632. info "Skipping ${BIN_DIR}/${cmd} symlink to k3s, command exists in PATH at ${which_cmd}"
  633. fi
  634. else
  635. info "Skipping ${BIN_DIR}/${cmd} symlink to k3s, already exists"
  636. fi
  637. done
  638. }
  639. # --- create killall script ---
  640. create_killall() {
  641. [ "${INSTALL_K3S_BIN_DIR_READ_ONLY}" = true ] && return
  642. info "Creating killall script ${KILLALL_K3S_SH}"
  643. $SUDO tee ${KILLALL_K3S_SH} >/dev/null << \EOF
  644. #!/bin/sh
  645. [ $(id -u) -eq 0 ] || exec sudo $0 $@
  646. for bin in /var/lib/rancher/k3s/data/**/bin/; do
  647. [ -d $bin ] && export PATH=$PATH:$bin:$bin/aux
  648. done
  649. set -x
  650. for service in /etc/systemd/system/k3s*.service; do
  651. [ -s $service ] && systemctl stop $(basename $service)
  652. done
  653. for service in /etc/init.d/k3s*; do
  654. [ -x $service ] && $service stop
  655. done
  656. pschildren() {
  657. ps -e -o ppid= -o pid= | \
  658. sed -e 's/^\s*//g; s/\s\s*/\t/g;' | \
  659. grep -w "^$1" | \
  660. cut -f2
  661. }
  662. pstree() {
  663. for pid in $@; do
  664. echo $pid
  665. for child in $(pschildren $pid); do
  666. pstree $child
  667. done
  668. done
  669. }
  670. killtree() {
  671. kill -9 $(
  672. { set +x; } 2>/dev/null;
  673. pstree $@;
  674. set -x;
  675. ) 2>/dev/null
  676. }
  677. remove_interfaces() {
  678. # Delete network interface(s) that match 'master cni0'
  679. ip link show 2>/dev/null | grep 'master cni0' | while read ignore iface ignore; do
  680. iface=${iface%%@*}
  681. [ -z "$iface" ] || ip link delete $iface
  682. done
  683. # Delete cni related interfaces
  684. ip link delete cni0
  685. ip link delete flannel.1
  686. ip link delete flannel-v6.1
  687. ip link delete kube-ipvs0
  688. ip link delete flannel-wg
  689. ip link delete flannel-wg-v6
  690. # Restart tailscale
  691. if [ -n "$(command -v tailscale)" ]; then
  692. tailscale set --advertise-routes=
  693. fi
  694. }
  695. getshims() {
  696. ps -e -o pid= -o args= | sed -e 's/^ *//; s/\s\s*/\t/;' | grep -w 'k3s/data/[^/]*/bin/containerd-shim' | cut -f1
  697. }
  698. killtree $({ set +x; } 2>/dev/null; getshims; set -x)
  699. do_unmount_and_remove() {
  700. set +x
  701. while read -r _ path _; do
  702. case "$path" in $1*) echo "$path" ;; esac
  703. done < /proc/self/mounts | sort -r | xargs -r -t -n 1 sh -c 'umount -f "$0" && rm -rf "$0"'
  704. set -x
  705. }
  706. do_unmount_and_remove '/run/k3s'
  707. do_unmount_and_remove '/var/lib/rancher/k3s'
  708. do_unmount_and_remove '/var/lib/kubelet/pods'
  709. do_unmount_and_remove '/var/lib/kubelet/plugins'
  710. do_unmount_and_remove '/run/netns/cni-'
  711. # Remove CNI namespaces
  712. ip netns show 2>/dev/null | grep cni- | xargs -r -t -n 1 ip netns delete
  713. remove_interfaces
  714. rm -rf /var/lib/cni/
  715. iptables-save | grep -v KUBE- | grep -v CNI- | grep -iv flannel | iptables-restore
  716. ip6tables-save | grep -v KUBE- | grep -v CNI- | grep -iv flannel | ip6tables-restore
  717. EOF
  718. $SUDO chmod 755 ${KILLALL_K3S_SH}
  719. $SUDO chown root:root ${KILLALL_K3S_SH}
  720. }
  721. # --- create uninstall script ---
  722. create_uninstall() {
  723. [ "${INSTALL_K3S_BIN_DIR_READ_ONLY}" = true ] && return
  724. info "Creating uninstall script ${UNINSTALL_K3S_SH}"
  725. $SUDO tee ${UNINSTALL_K3S_SH} >/dev/null << EOF
  726. #!/bin/sh
  727. set -x
  728. [ \$(id -u) -eq 0 ] || exec sudo \$0 \$@
  729. ${KILLALL_K3S_SH}
  730. if command -v systemctl; then
  731. systemctl disable ${SYSTEM_NAME}
  732. systemctl reset-failed ${SYSTEM_NAME}
  733. systemctl daemon-reload
  734. fi
  735. if command -v rc-update; then
  736. rc-update delete ${SYSTEM_NAME} default
  737. fi
  738. rm -f ${FILE_K3S_SERVICE}
  739. rm -f ${FILE_K3S_ENV}
  740. remove_uninstall() {
  741. rm -f ${UNINSTALL_K3S_SH}
  742. }
  743. trap remove_uninstall EXIT
  744. if (ls ${SYSTEMD_DIR}/k3s*.service || ls /etc/init.d/k3s*) >/dev/null 2>&1; then
  745. set +x; echo 'Additional k3s services installed, skipping uninstall of k3s'; set -x
  746. exit
  747. fi
  748. for cmd in kubectl crictl ctr; do
  749. if [ -L ${BIN_DIR}/\$cmd ]; then
  750. rm -f ${BIN_DIR}/\$cmd
  751. fi
  752. done
  753. rm -rf /etc/rancher/k3s
  754. rm -rf /run/k3s
  755. rm -rf /run/flannel
  756. rm -rf /var/lib/rancher/k3s
  757. rm -rf /var/lib/kubelet
  758. rm -f ${BIN_DIR}/k3s
  759. rm -f ${KILLALL_K3S_SH}
  760. if type yum >/dev/null 2>&1; then
  761. yum remove -y k3s-selinux
  762. rm -f /etc/yum.repos.d/rancher-k3s-common*.repo
  763. elif type rpm-ostree >/dev/null 2>&1; then
  764. rpm-ostree uninstall k3s-selinux
  765. rm -f /etc/yum.repos.d/rancher-k3s-common*.repo
  766. elif type zypper >/dev/null 2>&1; then
  767. uninstall_cmd="zypper remove -y k3s-selinux"
  768. if [ "\${TRANSACTIONAL_UPDATE=false}" != "true" ] && [ -x /usr/sbin/transactional-update ]; then
  769. uninstall_cmd="transactional-update --no-selfupdate -d run \$uninstall_cmd"
  770. fi
  771. \$uninstall_cmd
  772. rm -f /etc/zypp/repos.d/rancher-k3s-common*.repo
  773. fi
  774. EOF
  775. $SUDO chmod 755 ${UNINSTALL_K3S_SH}
  776. $SUDO chown root:root ${UNINSTALL_K3S_SH}
  777. }
  778. # --- disable current service if loaded --
  779. systemd_disable() {
  780. $SUDO systemctl disable ${SYSTEM_NAME} >/dev/null 2>&1 || true
  781. $SUDO rm -f /etc/systemd/system/${SERVICE_K3S} || true
  782. $SUDO rm -f /etc/systemd/system/${SERVICE_K3S}.env || true
  783. }
  784. # --- capture current env and create file containing k3s_ variables ---
  785. create_env_file() {
  786. info "env: Creating environment file ${FILE_K3S_ENV}"
  787. $SUDO touch ${FILE_K3S_ENV}
  788. $SUDO chmod 0600 ${FILE_K3S_ENV}
  789. sh -c export | while read x v; do echo $v; done | grep -E '^(K3S|CONTAINERD)_' | $SUDO tee ${FILE_K3S_ENV} >/dev/null
  790. sh -c export | while read x v; do echo $v; done | grep -Ei '^(NO|HTTP|HTTPS)_PROXY' | $SUDO tee -a ${FILE_K3S_ENV} >/dev/null
  791. }
  792. # --- write systemd service file ---
  793. create_systemd_service_file() {
  794. info "systemd: Creating service file ${FILE_K3S_SERVICE}"
  795. $SUDO tee ${FILE_K3S_SERVICE} >/dev/null << EOF
  796. [Unit]
  797. Description=Lightweight Kubernetes
  798. Documentation=https://k3s.io
  799. Wants=network-online.target
  800. After=network-online.target
  801. [Install]
  802. WantedBy=multi-user.target
  803. [Service]
  804. Type=${SYSTEMD_TYPE}
  805. EnvironmentFile=-/etc/default/%N
  806. EnvironmentFile=-/etc/sysconfig/%N
  807. EnvironmentFile=-${FILE_K3S_ENV}
  808. KillMode=process
  809. Delegate=yes
  810. # Having non-zero Limit*s causes performance problems due to accounting overhead
  811. # in the kernel. We recommend using cgroups to do container-local accounting.
  812. LimitNOFILE=1048576
  813. LimitNPROC=infinity
  814. LimitCORE=infinity
  815. TasksMax=infinity
  816. TimeoutStartSec=0
  817. Restart=always
  818. RestartSec=5s
  819. ExecStartPre=/bin/sh -xc '! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service 2>/dev/null'
  820. ExecStartPre=-/sbin/modprobe br_netfilter
  821. ExecStartPre=-/sbin/modprobe overlay
  822. ExecStart=${BIN_DIR}/k3s \\
  823. ${CMD_K3S_EXEC}
  824. EOF
  825. }
  826. # --- write openrc service file ---
  827. create_openrc_service_file() {
  828. LOG_FILE=/var/log/${SYSTEM_NAME}.log
  829. info "openrc: Creating service file ${FILE_K3S_SERVICE}"
  830. $SUDO tee ${FILE_K3S_SERVICE} >/dev/null << EOF
  831. #!/sbin/openrc-run
  832. depend() {
  833. after network-online
  834. want cgroups
  835. }
  836. start_pre() {
  837. rm -f /tmp/k3s.*
  838. }
  839. supervisor=supervise-daemon
  840. name=${SYSTEM_NAME}
  841. command="${BIN_DIR}/k3s"
  842. command_args="$(escape_dq "${CMD_K3S_EXEC}")
  843. >>${LOG_FILE} 2>&1"
  844. output_log=${LOG_FILE}
  845. error_log=${LOG_FILE}
  846. pidfile="/var/run/${SYSTEM_NAME}.pid"
  847. respawn_delay=5
  848. respawn_max=0
  849. set -o allexport
  850. if [ -f /etc/environment ]; then . /etc/environment; fi
  851. if [ -f ${FILE_K3S_ENV} ]; then . ${FILE_K3S_ENV}; fi
  852. set +o allexport
  853. EOF
  854. $SUDO chmod 0755 ${FILE_K3S_SERVICE}
  855. $SUDO tee /etc/logrotate.d/${SYSTEM_NAME} >/dev/null << EOF
  856. ${LOG_FILE} {
  857. missingok
  858. notifempty
  859. copytruncate
  860. }
  861. EOF
  862. }
  863. # --- write systemd or openrc service file ---
  864. create_service_file() {
  865. [ "${HAS_SYSTEMD}" = true ] && create_systemd_service_file && restore_systemd_service_file_context
  866. [ "${HAS_OPENRC}" = true ] && create_openrc_service_file
  867. return 0
  868. }
  869. restore_systemd_service_file_context() {
  870. $SUDO restorecon -R -i ${FILE_K3S_SERVICE} 2>/dev/null || true
  871. $SUDO restorecon -R -i ${FILE_K3S_ENV} 2>/dev/null || true
  872. }
  873. # --- get hashes of the current k3s bin and service files
  874. get_installed_hashes() {
  875. $SUDO sha256sum ${BIN_DIR}/k3s ${FILE_K3S_SERVICE} ${FILE_K3S_ENV} 2>&1 || true
  876. }
  877. # --- enable and start systemd service ---
  878. systemd_enable() {
  879. info "systemd: Enabling ${SYSTEM_NAME} unit"
  880. $SUDO systemctl enable ${FILE_K3S_SERVICE} >/dev/null
  881. $SUDO systemctl daemon-reload >/dev/null
  882. }
  883. systemd_start() {
  884. info "systemd: Starting ${SYSTEM_NAME}"
  885. $SUDO systemctl restart ${SYSTEM_NAME}
  886. }
  887. # --- enable and start openrc service ---
  888. openrc_enable() {
  889. info "openrc: Enabling ${SYSTEM_NAME} service for default runlevel"
  890. $SUDO rc-update add ${SYSTEM_NAME} default >/dev/null
  891. }
  892. openrc_start() {
  893. info "openrc: Starting ${SYSTEM_NAME}"
  894. $SUDO ${FILE_K3S_SERVICE} restart
  895. }
  896. has_working_xtables() {
  897. if command -v "$1-save" 1> /dev/null && command -v "$1-restore" 1> /dev/null; then
  898. if $SUDO $1-save 2>/dev/null | grep -q '^-A CNI-HOSTPORT-MASQ -j MASQUERADE$'; then
  899. warn "Host $1-save/$1-restore tools are incompatible with existing rules"
  900. else
  901. return 0
  902. fi
  903. else
  904. info "Host $1-save/$1-restore tools not found"
  905. fi
  906. return 1
  907. }
  908. # --- startup systemd or openrc service ---
  909. service_enable_and_start() {
  910. if [ -f "/proc/cgroups" ] && [ "$(grep memory /proc/cgroups | while read -r n n n enabled; do echo $enabled; done)" -eq 0 ];
  911. then
  912. info 'Failed to find memory cgroup, you may need to add "cgroup_memory=1 cgroup_enable=memory" to your linux cmdline (/boot/cmdline.txt on a Raspberry Pi)'
  913. fi
  914. [ "${INSTALL_K3S_SKIP_ENABLE}" = true ] && return
  915. [ "${HAS_SYSTEMD}" = true ] && systemd_enable
  916. [ "${HAS_OPENRC}" = true ] && openrc_enable
  917. [ "${INSTALL_K3S_SKIP_START}" = true ] && return
  918. POST_INSTALL_HASHES=$(get_installed_hashes)
  919. if [ "${PRE_INSTALL_HASHES}" = "${POST_INSTALL_HASHES}" ] && [ "${INSTALL_K3S_FORCE_RESTART}" != true ]; then
  920. info 'No change detected so skipping service start'
  921. return
  922. fi
  923. for XTABLES in iptables ip6tables; do
  924. if has_working_xtables ${XTABLES}; then
  925. $SUDO ${XTABLES}-save 2>/dev/null | grep -v KUBE- | grep -iv flannel | $SUDO ${XTABLES}-restore
  926. fi
  927. done
  928. [ "${HAS_SYSTEMD}" = true ] && systemd_start
  929. [ "${HAS_OPENRC}" = true ] && openrc_start
  930. return 0
  931. }
  932. # --- re-evaluate args to include env command ---
  933. eval set -- $(escape "${INSTALL_K3S_EXEC}") $(quote "$@")
  934. # --- run the install process --
  935. {
  936. verify_system
  937. setup_env "$@"
  938. download_and_verify
  939. setup_selinux
  940. create_symlinks
  941. create_killall
  942. create_uninstall
  943. systemd_disable
  944. create_env_file
  945. create_service_file
  946. service_enable_and_start
  947. }