├── .github └── workflows │ └── flowzone.yml ├── .gitignore ├── .resinci.yml ├── .versionbot └── CHANGELOG.yml ├── CHANGELOG.md ├── Dockerfile.template ├── README.md ├── package-lock.json ├── package.json └── src └── helloworld.js /.github/workflows/flowzone.yml: -------------------------------------------------------------------------------- 1 | name: Flowzone 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, closed] 6 | branches: [main, master] 7 | # allow external contributions to use secrets within trusted code 8 | pull_request_target: 9 | types: [opened, synchronize, closed] 10 | branches: [main, master] 11 | 12 | jobs: 13 | flowzone: 14 | name: Flowzone 15 | uses: product-os/flowzone/.github/workflows/flowzone.yml@master 16 | # prevent duplicate workflow executions for pull_request and pull_request_target 17 | if: | 18 | ( 19 | github.event.pull_request.head.repo.full_name == github.repository && 20 | github.event_name == 'pull_request' 21 | ) || ( 22 | github.event.pull_request.head.repo.full_name != github.repository && 23 | github.event_name == 'pull_request_target' 24 | ) 25 | secrets: inherit 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Numerous always-ignore extensions 2 | *.img 3 | *.diff 4 | *.err 5 | *.orig 6 | *.log 7 | *.rej 8 | *.swo 9 | *.swp 10 | *.zip 11 | *.vi 12 | *~ 13 | *.sass-cache 14 | .#* 15 | 16 | # OS or Editor folders 17 | .DS_Store 18 | ._* 19 | Thumbs.db 20 | .cache 21 | .project 22 | .settings 23 | .tmproj 24 | *.esproj 25 | nbproject 26 | *.sublime-project 27 | *.sublime-workspace 28 | .fasttest 29 | 30 | # Folders to ignore 31 | node_modules 32 | -------------------------------------------------------------------------------- /.resinci.yml: -------------------------------------------------------------------------------- 1 | npm: 2 | platforms: 3 | - name: linux 4 | os: alpine 5 | architecture: x86_64 6 | node_versions: 7 | - "14" 8 | -------------------------------------------------------------------------------- /.versionbot/CHANGELOG.yml: -------------------------------------------------------------------------------- 1 | - commits: 2 | - subject: Update commands for CLI v20 3 | hash: 881707ac6ac75b21c9321f6c29d374f035b4ecc3 4 | body: "" 5 | footer: 6 | Change-type: patch 7 | change-type: patch 8 | author: myarmolinsky 9 | version: 1.1.12 10 | title: "" 11 | date: 2025-02-07T13:05:03.360Z 12 | - commits: 13 | - subject: "patch: Update Dockerfile.template" 14 | hash: 0079712639160d082c3a061a5a9c22be860ea818 15 | body: "" 16 | footer: {} 17 | author: Vipul Gupta 18 | version: 1.1.11 19 | title: "" 20 | date: 2025-01-31T16:00:01.926Z 21 | - commits: 22 | - subject: 'patch: Update the activation of "Local Mode"' 23 | hash: 8e0c59c39136a4257453af93b73c28d7bc0dc89f 24 | body: "" 25 | footer: {} 26 | author: Markus Grunwald 27 | version: 1.1.10 28 | title: "" 29 | date: 2023-12-27T12:03:03.429Z 30 | - commits: 31 | - subject: "patch: Replace balenaFin link" 32 | hash: 6bda6ac22a9104a855fce85b59337a42851b6362 33 | body: "" 34 | footer: 35 | Signed-off-by: Vipul Gupta (@vipulgupta2048) 36 | signed-off-by: Vipul Gupta (@vipulgupta2048) 37 | author: Vipul Gupta (@vipulgupta2048) 38 | version: 1.1.9 39 | title: "" 40 | date: 2023-12-19T09:05:39.112Z 41 | - commits: 42 | - subject: "patch: Add Flowzone" 43 | hash: 93ed398079483e8c1cb7c72aea75a98e89ae697f 44 | body: "" 45 | footer: 46 | Signed-off-by: Vipul Gupta (@vipulgupta2048) 47 | signed-off-by: Vipul Gupta (@vipulgupta2048) 48 | author: Vipul Gupta (@vipulgupta2048) 49 | version: 1.1.8 50 | title: "" 51 | date: 2023-12-18T16:49:39.275Z 52 | - version: 1.1.7 53 | date: 2022-01-19T14:08:08Z 54 | commits: 55 | - hash: e5aa90e93d594347c684ee507404c7df26554c63 56 | author: Bernhard Kaindl 57 | footers: 58 | change-type: patch 59 | subject: Update the fleet output messages 60 | body: "" 61 | - hash: 14ebbb9d0351de9338725df79ce47f80b6a9f7da 62 | author: Bernhard Kaindl 63 | subject: Apply review findings 64 | body: "" 65 | - version: 1.1.6 66 | date: 2021-10-18T16:49:15Z 67 | commits: 68 | - hash: 30448117c07ee5753fa5ad4c820474eef3658260 69 | author: David Tischler 70 | subject: Rename Application to Fleet 71 | body: "patch: Updated Readme.md" 72 | - hash: 9d4ab3cb5df8cc0e9a7f0fc5a9360a003db760d6 73 | author: Vipul Gupta (@vipulgupta2048) 74 | footers: 75 | signed-off-by: Vipul Gupta (@vipulgupta2048) 76 | subject: "patch: Update fleet terminology for more instances" 77 | body: "" 78 | - hash: 3407a56ddacbcdf9d31d05ebe34328e721d9d23e 79 | author: dtischler 80 | footers: 81 | co-authored-by: Vipul Gupta 82 | subject: Update README.md 83 | body: "" 84 | - hash: 97af64bc26836540f5b03f89a69dc3de1862c97a 85 | author: dtischler 86 | footers: 87 | co-authored-by: Vipul Gupta 88 | subject: Update README.md 89 | body: "" 90 | - hash: 6ef6203daaad951c3b5a40cfbb47a1864afd5da5 91 | author: dtischler 92 | footers: 93 | co-authored-by: Vipul Gupta 94 | subject: Update README.md 95 | body: "" 96 | - hash: 6eed69f0084b7821ccceb6c6d424d53c4c6eb3fb 97 | author: dtischler 98 | footers: 99 | co-authored-by: Vipul Gupta 100 | subject: Update README.md 101 | body: "" 102 | - hash: 3712d05b45e2e36e963b6a3912638f18f5104c67 103 | author: dtischler 104 | footers: 105 | co-authored-by: Vipul Gupta 106 | subject: Update README.md 107 | body: "" 108 | - hash: f0b7069810d065316f1060b534f2a47cdae3d50a 109 | author: dtischler 110 | footers: 111 | co-authored-by: Vipul Gupta 112 | subject: Update README.md 113 | body: "" 114 | - hash: 0eb6387bbea90073b90cd50da718fb327650e3e4 115 | author: dtischler 116 | footers: 117 | co-authored-by: Vipul Gupta 118 | subject: Update README.md 119 | body: "" 120 | - hash: ac446d292e958da77c97d67385ca78761d71a778 121 | author: dtischler 122 | footers: 123 | co-authored-by: Vipul Gupta 124 | subject: Update README.md 125 | body: "" 126 | - hash: b8a4af1652b2561640758b0ed711407368408bee 127 | author: dtischler 128 | footers: 129 | co-authored-by: Vipul Gupta 130 | subject: Update README.md 131 | body: "" 132 | - hash: 5098b95fcd4eaff6e374c647b51594a582cf5cc8 133 | author: dtischler 134 | footers: 135 | co-authored-by: Vipul Gupta 136 | subject: Update README.md 137 | body: "" 138 | - hash: df2494d82e6a9bf9f9e3e54a125ff92052be7fcf 139 | author: dtischler 140 | footers: 141 | co-authored-by: Vipul Gupta 142 | subject: Update README.md 143 | body: "" 144 | - hash: bb552ff29db529649c58cf19b3c32bd388d0ecf1 145 | author: dtischler 146 | footers: 147 | co-authored-by: Vipul Gupta 148 | subject: Update README.md 149 | body: "" 150 | - version: 1.1.5 151 | date: 2021-07-01T09:02:38Z 152 | commits: 153 | - hash: 262a72a8dc7c583ae107a0b6f41ae7ff6a556106 154 | author: dfunckt 155 | footers: 156 | change-type: patch 157 | subject: Delete .github directory 158 | body: "" 159 | - version: 1.1.4 160 | date: 2021-06-29T22:09:20Z 161 | commits: 162 | - hash: e1c6c050ee8485bc5ea94afb9f0b7350b6fae979 163 | author: Matthew Yarmolinsky 164 | footers: 165 | change-type: patch 166 | signed-off-by: Matthew Yarmolinsky 167 | subject: Replace git push and balena push sections with references 168 | body: "Replace git push and balena push sections with references\r 169 | 170 | \r" 171 | - version: 1.1.3 172 | date: 2021-04-08T17:19:14Z 173 | commits: 174 | - hash: 6cf83162e5246ce056ce0adbd8f85b950d9f3126 175 | author: Vipul Gupta 176 | subject: "patch: Fix typo" 177 | body: "" 178 | - version: 1.1.2 179 | date: 2021-04-07T17:16:34Z 180 | commits: 181 | - hash: 73b452a2e8cc4d732a34cff20f72c33354ddac57 182 | author: Marios Balamatsias 183 | footers: 184 | resolves: https://github.com/balena-io/docs/issues/1733 185 | change-type: patch 186 | subject: Fix typos in cli masterclass 187 | body: "" 188 | - version: 1.1.1 189 | date: 2021-01-13T14:51:38Z 190 | commits: 191 | - hash: 3ed29dc954fd997bc6f62da61c8bc7be6372c676 192 | author: AlidaOdendaal 193 | footers: 194 | change-type: patch 195 | signed-off-by: AlidaOdendaal alida@balena.io 196 | subject: Update README.md 197 | body: Insert the link to the balena CLI installation instructions. 198 | - hash: 8728d9facf34c9945d4a4d663e2e3c279f49c71a 199 | author: AlidaOdendaal 200 | footers: 201 | change-type: patch 202 | signed-off-by: AlidaOdendaal 203 | subject: Configure not to run checks for node versions < 14 204 | body: "" 205 | - version: 1.1.0 206 | date: 2020-05-29T07:14:07Z 207 | commits: 208 | - hash: 957c7003cb519dc76de2965cecd09ea889b805c6 209 | author: Vipul Gupta 210 | footers: 211 | change-type: minor 212 | signed-off-by: Vipul Gupta (@vipulgupta2048) 213 | subject: Add instructions to add SSH key to BalenaCloud 214 | body: "" 215 | - version: 1.0.20 216 | date: 2020-05-27T11:53:17Z 217 | commits: 218 | - hash: eb7ac26b5edeb45f2e5c8d76c33c65bd93a92726 219 | author: Matthew McGinn 220 | footers: 221 | connects-to: "#27" 222 | change-type: patch 223 | signed-off-by: Matthew McGinn 224 | subject: fix up broken fin link 225 | body: "" 226 | - version: 1.0.19 227 | date: 2020-05-08T20:01:00Z 228 | commits: 229 | - hash: b7b8def5bd41792b85f9e60d36e15f85dd39b645 230 | author: Gareth Davies 231 | footers: 232 | change-type: patch 233 | signed-off-by: Gareth Davies 234 | subject: Removing Gareth from codeowners 235 | body: "" 236 | - version: 1.0.18 237 | date: 2020-04-30T19:41:20Z 238 | commits: 239 | - hash: 82873af0f26e1e52c9fc02e91de4320f46170ca6 240 | author: Carlo Miguel Cruz 241 | footers: 242 | change-type: patch 243 | signed-off-by: Carlo Miguel Cruz 244 | subject: Adds command to see device architecture. 245 | body: "Since the balena build command requires the architecture and device type, 246 | we should indicate the command `balena devices supported -v` that shows 247 | the architecture of each supported device.\r 248 | 249 | \r" 250 | - version: 1.0.17 251 | date: 2020-04-30T15:54:51Z 252 | commits: 253 | - hash: 5c1492f4d3624df1572db9d478f4d1037e5b91e0 254 | author: Carlo Miguel Cruz 255 | footers: 256 | change-type: patch 257 | signed-off-by: Carlo Miguel Cruz 258 | subject: Updates README.md. 259 | body: Line 561 should be `balena build` instead of `balena push` as it refers to 260 | the build command. 261 | - version: 1.0.16 262 | date: 2020-04-20T19:37:01Z 263 | commits: 264 | - hash: 2f1c2ac80db3c96be0796b4ba81dd7d2dd7411ac 265 | author: Matthew McGinn 266 | footers: 267 | change-type: patch 268 | signed-off-by: Matthew McGinn 269 | subject: remove hedss as codeowner 270 | body: "" 271 | - version: 1.0.15 272 | date: 2020-02-19T12:35:46Z 273 | commits: 274 | - hash: 0f6b2e590faeacda1079c75701ecedfa75408cb8 275 | author: Josh Bowling 276 | footers: 277 | change-type: patch 278 | signed-off-by: Josh Bowling 279 | subject: Fix small typo in readme 280 | body: "" 281 | - version: 1.0.14 282 | date: 2020-02-12T19:53:56Z 283 | commits: 284 | - hash: 9d9a6cfb2ea5ea0042703e2a8e3069c4a9dc5d81 285 | author: Gareth Davies 286 | footers: 287 | change-type: patch 288 | signed-off-by: Gareth Davies gareth@balena.io 289 | subject: "meta: Formatting using markdownlint" 290 | body: "" 291 | - hash: 16724c09f463cfebf25ef4af7d847b93e8ccecc1 292 | author: Matthew McGinn 293 | footers: 294 | change-type: patch 295 | signed-off-by: Matthew McGinn 296 | subject: minor spelling/formatting updates 297 | body: "" 298 | - version: 1.0.13 299 | date: 2020-01-07T11:01:42Z 300 | commits: 301 | - hash: f278a6d31eab1764d2c852b7df87e4eef21a86dd 302 | author: Heds Simons 303 | footers: 304 | change-type: patch 305 | signed-off-by: Heds Simons 306 | subject: "readme: Ensure service log example outputs something" 307 | body: "" 308 | - version: 1.0.12 309 | date: 2020-01-07T10:53:36Z 310 | commits: 311 | - hash: ceb85f510ae6f6e268db286e9c2a5b5d186a9625 312 | author: Heds Simons 313 | footers: 314 | change-type: patch 315 | signed-off-by: Heds Simons 316 | subject: "org: Change from balena-io-projects to balena-io" 317 | body: "" 318 | - version: 1.0.11 319 | date: 2019-12-11T16:12:28Z 320 | commits: 321 | - hash: 020abf239c49333b2ac36cfb4a28743be5e3d271 322 | author: Gareth Davies 323 | footers: 324 | change-type: patch 325 | signed-off-by: Gareth Davies 326 | subject: "docs: Rename balenaCLI to balena CLI" 327 | body: "" 328 | - version: 1.0.10 329 | date: 2019-11-22T10:21:14Z 330 | commits: 331 | - hash: 447f360d3a8a764c18bba52384f54eaca7a992ba 332 | author: Heds Simons 333 | footers: 334 | change-type: patch 335 | signed-off-by: Heds Simons 336 | subject: "readme: Note that Docker should be installed" 337 | body: "" 338 | - version: 1.0.9 339 | date: 2019-11-18T10:21:44Z 340 | commits: 341 | - hash: 357532f2a7bde98d00fe74e55e7781027676a9b5 342 | author: Federico Fissore 343 | footers: 344 | change-type: patch 345 | signed-off-by: Federico Fissore 346 | subject: "Pushing Code to a Device: small fixes to README.md" 347 | body: "" 348 | - version: 1.0.8 349 | date: 2019-11-18T09:09:04Z 350 | commits: 351 | - hash: e5c81928b36dd4a25eca89ea393a2a18c7cfc48f 352 | author: Heds Simons 353 | footers: 354 | change-type: patch 355 | signed-off-by: Heds Simons 356 | subject: "package: Ensure `private` field is a boolean" 357 | body: "" 358 | - version: 1.0.7 359 | date: 2019-11-15T12:00:46Z 360 | commits: 361 | - hash: 4981be90c54e2dd735eeb14df364d03bf18702e2 362 | author: Federico Fissore 363 | footers: 364 | change-type: patch 365 | signed-off-by: Federico Fissore 366 | subject: "1.1 Installation: mentioning `--unsafe-perm` npm param" 367 | body: |- 368 | Add `--unsafe-perm` param to npm command line if you get a EACCESS 369 | permission denied error 370 | - version: 1.0.6 371 | date: 2019-11-05T17:33:03Z 372 | commits: 373 | - hash: 9e88fd747146a462a56a297ff139527d2bb53dfb 374 | author: Heds Simons 375 | footers: 376 | change-type: patch 377 | signed-off-by: Heds Simons 378 | subject: "readme/.gitignore: Update README to add repo details and add .gitignore" 379 | body: "" 380 | - hash: 2e41636f14aeafa974e1db102ab75639bbffe13f 381 | author: Gareth Davies 382 | footers: 383 | change-type: patch 384 | signed-off-by: Gareth Davies gareth@balena.io 385 | subject: Minor formatting 386 | body: "Closes #7" 387 | - version: 1.0.5 388 | date: 2019-10-30T13:32:14Z 389 | commits: 390 | - hash: d72be4081305f880531ae6e27c0747ac58a73783 391 | author: Tomás Migone 392 | footers: 393 | change-type: patch 394 | signed-off-by: Tomás Migone 395 | subject: Clarify YAML structure for service specific secrets. 396 | body: "" 397 | - version: 1.0.4 398 | date: 2019-10-30T11:41:56Z 399 | commits: 400 | - hash: 77e7bdc4364e25357d63c081846ec13261e16fdc 401 | author: Matthew McGinn 402 | footers: 403 | signed-off-by: Matthew McGinn 404 | change-type: patch 405 | subject: "meta: add CODEOWNERS" 406 | body: "" 407 | - version: 1.0.3 408 | date: 2019-10-30T10:01:36Z 409 | commits: 410 | - hash: 937f7a5ffd7fc58ba3a8eab29a8fb2911e80e18c 411 | author: AlidaOdendaal 412 | footers: 413 | change-type: patch 414 | signed-off-by: AlidaOdendaal 415 | subject: Fix minor typos 416 | body: "" 417 | - version: 1.0.2 418 | date: 2019-10-22T14:53:34Z 419 | commits: 420 | - hash: b990bb4e447eb3b08b6dd54a972ecbbb777df7f2 421 | author: Heds Simons 422 | footers: 423 | change-type: patch 424 | signed-off-by: Heds Simons 425 | subject: "dockerfile: Update to use recursive dir removal." 426 | body: "" 427 | - version: 1.0.1 428 | date: 2019-09-30T12:52:32Z 429 | commits: 430 | - hash: 6f5ccd05ebf52d96dbfbb65588f82cd4e7faf076 431 | author: Heds Simons 432 | footers: 433 | change-type: patch 434 | signed-off-by: Heds Simons 435 | subject: "npm: Ensure package isn't published" 436 | body: "" 437 | - version: 1.0.0 438 | date: 2019-09-30T12:38:08Z 439 | commits: 440 | - hash: 1227f9ca839514662dce50964fd261fa596f2c0b 441 | author: Heds Simons 442 | footers: 443 | change-type: major 444 | signed-off-by: Heds Simons 445 | subject: "masterclass: Initial PR for balenaCLI masterclass" 446 | body: "" 447 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file 4 | automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY! 5 | This project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | # v1.1.12 8 | ## (2025-02-07) 9 | 10 | * Update commands for CLI v20 [myarmolinsky] 11 | 12 | # v1.1.11 13 | ## (2025-01-31) 14 | 15 | * patch: Update Dockerfile.template [Vipul Gupta] 16 | 17 | # v1.1.10 18 | ## (2023-12-27) 19 | 20 | * patch: Update the activation of "Local Mode" [Markus Grunwald] 21 | 22 | # v1.1.9 23 | ## (2023-12-19) 24 | 25 | * patch: Replace balenaFin link [Vipul Gupta (@vipulgupta2048)] 26 | 27 | # v1.1.8 28 | ## (2023-12-18) 29 | 30 | * patch: Add Flowzone [Vipul Gupta (@vipulgupta2048)] 31 | 32 | # v1.1.7 33 | ## (2022-01-19) 34 | 35 | * Update the fleet output messages [Bernhard Kaindl] 36 | 37 | # v1.1.6 38 | ## (2021-08-12) 39 | 40 | * patch: Update fleet terminology for more instances [Vipul Gupta (@vipulgupta2048)] 41 | 42 | # v1.1.5 43 | ## (2021-07-01) 44 | 45 | * Delete .github directory [dfunckt] 46 | 47 | # v1.1.4 48 | ## (2021-06-29) 49 | 50 | * Replace git push and balena push sections with references [Matthew Yarmolinsky] 51 | 52 | # v1.1.3 53 | ## (2021-04-08) 54 | 55 | * patch: Fix typo [Vipul Gupta] 56 | 57 | # v1.1.2 58 | ## (2021-03-30) 59 | 60 | * Fix typos in cli masterclass [Marios Balamatsias] 61 | 62 | # v1.1.1 63 | ## (2021-01-13) 64 | 65 | * Configure not to run checks for node versions < 14 [AlidaOdendaal] 66 | * Update README.md [AlidaOdendaal] 67 | 68 | # v1.1.0 69 | ## (2020-05-29) 70 | 71 | * Add instructions to add SSH key to BalenaCloud [Vipul Gupta] 72 | 73 | # v1.0.20 74 | ## (2020-05-27) 75 | 76 | * fix up broken fin link [Matthew McGinn] 77 | 78 | # v1.0.19 79 | ## (2020-05-08) 80 | 81 | * Removing Gareth from codeowners [Gareth Davies] 82 | 83 | # v1.0.18 84 | ## (2020-04-30) 85 | 86 | * Adds command to see device architecture. [Carlo Miguel Cruz] 87 | 88 | # v1.0.17 89 | ## (2020-04-30) 90 | 91 | * Updates README.md. [Carlo Miguel Cruz] 92 | 93 | # v1.0.16 94 | ## (2020-04-20) 95 | 96 | * remove hedss as codeowner [Matthew McGinn] 97 | 98 | ## 1.0.15 - 2020-02-19 99 | 100 | * Fix small typo in readme [Josh Bowling] 101 | 102 | ## 1.0.14 - 2020-02-12 103 | 104 | * Meta: Formatting using markdownlint [Gareth Davies] 105 | * Minor spelling/formatting updates [Matthew McGinn] 106 | 107 | ## 1.0.13 - 2020-01-07 108 | 109 | * Readme: Ensure service log example outputs something [Heds Simons] 110 | 111 | ## 1.0.12 - 2020-01-06 112 | 113 | * Org: Change from balena-io-projects to balena-io [Heds Simons] 114 | 115 | ## 1.0.11 - 2019-12-02 116 | 117 | * Docs: Rename balenaCLI to balena CLI [Gareth Davies] 118 | 119 | ## 1.0.10 - 2019-11-22 120 | 121 | * Readme: Note that Docker should be installed [Heds Simons] 122 | 123 | ## 1.0.9 - 2019-11-18 124 | 125 | * Pushing Code to a Device: small fixes to README.md [Federico Fissore] 126 | 127 | ## 1.0.8 - 2019-11-15 128 | 129 | * Package: Ensure `private` field is a boolean [Heds Simons] 130 | 131 | ## 1.0.7 - 2019-11-15 132 | 133 | * 1.1 Installation: mentioning `--unsafe-perm` npm param [Federico Fissore] 134 | 135 | ## 1.0.6 - 2019-11-08 136 | 137 | * Minor formatting [Gareth Davies] 138 | * Readme/.gitignore: Update README to add repo details and add .gitignore [Heds Simons] 139 | 140 | ## 1.0.5 - 2019-10-30 141 | 142 | * Clarify YAML structure for service specific secrets. [Tomás Migone] 143 | 144 | ## 1.0.4 - 2019-10-30 145 | 146 | * Meta: add CODEOWNERS [Matthew McGinn] 147 | 148 | ## 1.0.3 - 2019-10-30 149 | 150 | * Fix minor typos [AlidaOdendaal] 151 | 152 | ## 1.0.2 - 2019-10-22 153 | 154 | * Dockerfile: Update to use recursive dir removal. [Heds Simons] 155 | 156 | ## 1.0.1 - 2019-09-30 157 | 158 | * Npm: Ensure package isn't published [Heds Simons] 159 | 160 | ## 1.0.0 - 2019-09-30 161 | 162 | * Masterclass: Initial PR for balenaCLI masterclass [Heds Simons] 163 | -------------------------------------------------------------------------------- /Dockerfile.template: -------------------------------------------------------------------------------- 1 | FROM balenalib/%%BALENA_MACHINE_NAME%%-node:latest 2 | 3 | WORKDIR /usr/src/app 4 | 5 | COPY package.json package-lock.json ./ 6 | 7 | RUN npm install --ci --production \ 8 | && npm cache clean --force \ 9 | && rm -rf /tmp/* 10 | 11 | COPY src/ ./src/ 12 | 13 | CMD ["npm", "start"] 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Balena CLI Masterclass 2 | 3 | * **Masterclass Type:** Core 4 | * **Maximum Expected Time To Complete:** 60 minutes 5 | 6 | ## Introduction 7 | 8 | The balena Command Line Interface (balena CLI) utility consists of a number 9 | of commands that allow a user to develop, deploy and manage balena fleets, as 10 | well as manage configuration & variables of the fleet and balenaOS images. 11 | 12 | Almost everything that can be achieved via the balenaCloud dashboard can also be 13 | achieved via the balena CLI. 14 | 15 | In this masterclass, you will learn how to: 16 | 17 | * Login to your account 18 | * Push your first release to a balena fleet 19 | * Deploy locally built code to a balena fleet 20 | * SSH into a balena device 21 | * Push and build a release on the device over local network for fast 22 | development and prototyping 23 | * Use private Docker registries for base images and services 24 | * Create secret files and build arguments for building service images 25 | 26 | If you have any questions about this masterclass as you proceed through it, 27 | or would like clarifications on any of the topics raised here, please do 28 | raise an issue as on the repository this file is contained in, or contact 29 | us on the [balena forums](https://forums.balena.io/) where we'll be 30 | delighted to answer your questions. 31 | 32 | The location of the repository that contains this masterclass and all associated 33 | code is 34 | [https://github.com/balena-io/balena-cli-masterclass](https://github.com/balena-io/balena-cli-masterclass). 35 | 36 | ## Hardware and Software Requirements 37 | 38 | It is assumed that the reader has access to the following: 39 | 40 | * A locally cloned copy of this repository 41 | [Balena CLI Masterclass](https://github.com/balena-io/balena-cli-masterclass). 42 | Either: 43 | * `git clone https://github.com/balena-io/balena-cli-masterclass.git` 44 | * Download ZIP file (from 'Clone or download'->'Download ZIP') and then unzip it to a suitable directory 45 | * A balena supported device, such as a [Raspberry Pi 5](https://www.raspberrypi.org/products/raspberry-pi-5/) 46 | or [Intel NUC](https://www.intel.co.uk/content/www/uk/en/products/boards-kits/nuc.html). If you don't have a device, you can emulate an Intel NUC by 47 | installing VirtualBox and following [this guide](https://www.balena.io/blog/no-hardware-use-virtualbox/) 48 | * A suitable text editor for developing code on your development platform (eg. 49 | [Visual Code](https://code.visualstudio.com/)) 50 | * A suitable shell environment for command execution (such as `bash`) 51 | * A [balenaCloud](https://www.balena.io/) account 52 | * A local installation of [Docker](https://docs.docker.com/v17.09/engine/installation/) 53 | as well as a familiarity with [Dockerfiles](https://docs.docker.com/engine/reference/builder/) 54 | * Should you wish to install via `npm`, a [NodeJS](https://nodejs.org/en/) 55 | installation, including [NPM](https://www.npmjs.com/get-npm) is required. 56 | The use of [`nvm`](https://github.com/nvm-sh/nvm) 57 | is recommended, which allows you to alter the version of Node/NPM being used 58 | per-user, and also removes the need to install global dependencies using 59 | `sudo` 60 | 61 | ## Exercises 62 | 63 | All of the following exercises assume that you are running the balena CLI from 64 | a suitable Unix-based shell. The exercises include commands which can be run 65 | in such a shell and are represented by a line prefixed with `$`. Information 66 | returned from the execution of a command may be appended under the line to show 67 | what might be returned. For example: 68 | 69 | ```shell 70 | $ balena version 71 | 11.9.3 72 | ``` 73 | 74 | ### 1. Installation and Authentication 75 | 76 | #### 1.1 Installation 77 | 78 | First, we need to install balena CLI. The easiest way to achieve this is to use 79 | the installers for your OS from the 80 | [balena CLI releases page](https://github.com/balena-io/balena-cli/releases). 81 | Choose the installer for your OS, download it, and follow [the instructions](https://github.com/balena-io/balena-cli/blob/master/INSTALL.md). 82 | Note that there is not currently an installer for Linux, but you 83 | can download the standalone binary and then move it to a relevant location. 84 | 85 | The alternative way to install it is via `npm` on a system running NodeJS. 86 | Open a terminal on your development machine and run the following command: 87 | 88 | ```shell 89 | $ npm --global install balena-cli 90 | ``` 91 | 92 | This will install the balena CLI globally and allow you to run it in a terminal 93 | via `balena `. Note that, depending on how you've installed NodeJS 94 | and NPM, you may need to prefix this command with `sudo`. Also, if you get an 95 | error such as `EACCES: permission denied`, add param `--unsafe-perm` right 96 | after `--global` 97 | 98 | #### 1.2 Authentication 99 | 100 | To use balena CLI, you need to log into a balenaCloud account. If you don't 101 | have one, you can use the dashboard 102 | [here](https://dashboard.balena-cloud.com/signup) or sign up with the 103 | login command by selecting `I don't have a balena account!`. Either way, 104 | login via the terminal: 105 | 106 | ```shell 107 | $ balena login 108 | _ _ 109 | | |__ __ _ | | ____ _ __ __ _ 110 | | '_ \ / _` || | / __ \| '_ \ / _` | 111 | | |_) | (_) || || ___/| | | || (_) | 112 | |_.__/ \__,_||_| \____/|_| |_| \__,_| 113 | 114 | 115 | Logging in to balena-cloud.com 116 | ? How would you like to login? (Use arrow keys) 117 | ❯ Web authorization (recommended) 118 | Credentials 119 | Authentication token 120 | I don't have a balena account! 121 | ``` 122 | 123 | You will be asked how you wish to authenticate with balenaCloud. The 124 | easiest method is that of 'Web authorization' which will bring up a browser 125 | window (and ask you to first login to balenaCloud if you have not) and ask you 126 | to confirm you wish to login. 127 | 128 | Other authentication methods include using your username and password 129 | credentials or authentication token. Authentication tokens come in two types, 130 | API tokens and JSON Web Token (JWT) session tokens. Whilst API tokens do not 131 | expire, JWT session tokens do after 7 days. 132 | 133 | Once logged in, a [JWT](https://jwt.io/) session token will be saved in your 134 | home directory (`~/.balena/token`). Be aware that the lifetime of a balena 135 | JWT is limited to seven days, after which time reauthentication will be 136 | required. 137 | 138 | ### 2. Creating a Fleet and Provisioning a Device 139 | 140 | #### 2.1 Creating a Fleet 141 | 142 | Fleets can be created via the dashboard or via the balena CLI. We're going 143 | to create a new fleet via balena CLI called `cliFleet`. Run the following 144 | command: 145 | 146 | ```shell 147 | $ balena fleet create cliFleet 148 | ``` 149 | 150 | This will ask you which device type you wish to create the fleet for. 151 | You can scroll up and down this list using the arrow keys. For now, exit 152 | the command by hitting `Ctrl-C`, as there's another, non-interactive way to 153 | do this which we'll use instead. Type: 154 | 155 | ```shell 156 | $ balena device-type list 157 | ``` 158 | 159 | to see a list of all supported device types by balenaCloud. For the rest of 160 | this masterclass we're going to assume you're using a balenaFin, but you can 161 | just as easily use any supported balena device. 162 | We'll pass the balenaFin device type (`fincm3`) to the fleet creation 163 | command directly: 164 | 165 | ```shell 166 | $ balena fleet create cliFleet --type fincm3 167 | Fleet created: slug "admin/clifleet", device type "fincm3" 168 | ``` 169 | 170 | As can be seen, this will return the fleet's slug and device type. 171 | If you're using a different device type, pass the appropriate device type 172 | to the `balena fleet create` command instead. 173 | 174 | Non-interactive commands are useful when you need to script actions via 175 | balena CLI for a shell script (although balena also includes HTTPS endpoints and 176 | SDKs which can be used for this purpose). 177 | 178 | You can list the fleets currently owned by (or shared with) your account 179 | by typing: 180 | 181 | ```shell 182 | $ balena fleet list 183 | ID NAME SLUG DEVICE TYPE ONLINE DEVICES DEVICE COUNT 184 | 1234567 cliFleet admin/clifleet fincm3 0 0 185 | ``` 186 | 187 | #### 2.2 Provisioning a Device 188 | 189 | You can now provision your balenaFin by downloading a provisioning image from 190 | the balenaCloud dashboard. Be sure to download a development image, as we'll 191 | be utilizing its features later. 192 | 193 | Once the provisioning image is downloaded, connect your balenaFin to your development machine and run 194 | [Etcher](https://www.balena.io/etcher/) 195 | to 196 | [flash it](https://www.balena.io/fin/1.1/docs/getting-started/#Flashing-the-OS). 197 | 198 | Once the image has been flashed to the balenaFin it will register itself and 199 | connect to the balenaCloud VPN, showing up in the dashboard and being viewable 200 | using balena CLI: 201 | 202 | ```shell 203 | $ balena device list 204 | ID UUID DEVICE NAME DEVICE TYPE FLEET NAME STATUS IS ONLINE SUPERVISOR VERSION OS VERSION DASHBOARD URL 205 | 7654321 1234567 restless-glade fincm3 cliFleet true https://dashboard.balena-cloud.com/devices/12345678901234567890123456789012/summary 206 | ``` 207 | 208 | You can get detailed information on a device by using its Universally Unique 209 | Identifier (UUID), for example: 210 | 211 | ```shell 212 | $ balena device 1234567 213 | == RESTLESS GLADE 214 | ID: 7654321 215 | DEVICE TYPE: fincm3 216 | STATUS: idle 217 | IS ONLINE: true 218 | IP ADDRESS: 192.168.1.173 219 | FLEET NAME: cliFleet 220 | UUID: 12345678901234567890123456789012 221 | SUPERVISOR VERSION: 9.15.7 222 | IS WEB ACCESSIBLE: false 223 | OS VERSION: balenaOS 2.38.0+rev1 224 | DASHBOARD URL: https://dashboard.balena-cloud.com/devices/12345678901234567890123456789012/summary 225 | ``` 226 | 227 | UUIDs can either be used in their shortened version (as above) or in their 228 | long version (for example, the `DASHBOARD URL` field in the output above 229 | shows the entire UUID for the device). 230 | 231 | Be aware that there are ways to download, configure and provision a fleet 232 | image via balena CLI, but as some extra work is required to create a provisioning 233 | image (to allow greater flexibility) we'll go into that in the advanced 234 | masterclass. 235 | 236 | ### 3. Pushing Code to a Device 237 | 238 | Once a fleet has been created, we want to be able to push a release to it. 239 | There are a couple of ways to do this, but the most common is that of using 240 | `balena push`. See the [balena push](https://www.balena.io/docs/learn/deploy/deployment/#balena-push) docs to learn more about the command. 241 | Alternatively, you can use legacy method of pushing code via `git push`. You 242 | can learn about how to do so by going to the [git push](https://www.balena.io/docs/learn/deploy/deployment/#git-push) docs. Before moving 243 | on to the next step, make sure you know how to push code to a device. 244 | 245 | ### 4. SSHing into a Device 246 | 247 | Once a device has been provisioned, it can be accessed by SSHing into it via the 248 | balenaCloud VPN. To do this, you need to [add your public SSH key](https://www.balena.io/docs/learn/manage/ssh-access/#add-an-ssh-key-to-balenacloud) to your BalenaCloud 249 | account. When added, specify the UUID of the device you want to SSH into 250 | (remember you can see all your devices by running `balena device list`). 251 | 252 | ```shell 253 | $ balena device ssh 1234567 254 | ============================================================= 255 | Welcome to balenaOS 256 | ============================================================= 257 | root@827b231:~# 258 | ``` 259 | 260 | By default, SSH access is routed into the host balenaOS shell. However, you 261 | can SSH into a service by specifying its name as part of the command: 262 | 263 | ```shell 264 | $ balena device ssh 1234567 main 265 | root@827b231:/usr/src/app# 266 | ``` 267 | 268 | This also works in multi-container fleets, simply pass the name of the 269 | appropriate service as defined in `docker-compose.yml` you'd like to access 270 | the shell for. 271 | 272 | When using device UUIDs, `balena device ssh` uses the balena VPN to create a secure 273 | tunnel to the device and then forward SSH traffic between it and your 274 | development machine (for production devices, this is the only available method). 275 | 276 | For devices running development images on your local network, you can also 277 | use SSH by specifying the hostname or IP address of that device (development 278 | images have SSH enabled by default). Using `balena device ssh` in this way doesn't use 279 | the balena VPN and instead makes a direct SSH connection to the device. 280 | For example: 281 | 282 | ```shell 283 | $ balena device ssh 192.168.1.2 284 | ``` 285 | 286 | To find the hostname of a local development device, you can use `balena device detect`: 287 | 288 | ```shell 289 | $ sudo balena device detect 290 | Reporting scan results 291 | - 292 | host: 827b231.local 293 | address: 192.168.1.173 294 | dockerInfo: 295 | Containers: 1 296 | ContainersRunning: 1 297 | ContainersPaused: 0 298 | ContainersStopped: 0 299 | Images: 2 300 | Driver: aufs 301 | SystemTime: 2019-09-05T13:31:34.910619617Z 302 | KernelVersion: 4.14.98 303 | OperatingSystem: balenaOS 2.38.0+rev1 304 | Architecture: armv7l 305 | dockerVersion: 306 | Version: 18.09.6-dev 307 | ApiVersion: 1.39 308 | ``` 309 | 310 | In this instance `827b231.local` is the hostname, so the device can be SSHd 311 | into using `balena device ssh 827b231.local`. Note that by default, the hostname 312 | of a device is always its short UUID, so if you already know the UUID for the 313 | device, you can `balena device ssh .local` without having to perform a 314 | `balena device detect`. 315 | 316 | ### 5. Building and Deploying a release without the Builder 317 | 318 | #### 5.1 Building an Image on a Development Machine 319 | 320 | Whilst you can build the release image using the balenaCloud builder, it's also 321 | possible to build and generate the release's Docker images locally 322 | on your development machine. 323 | 324 | There are several reasons why you want might to do this. For example, should 325 | your development machine exist on an air-gapped network (with no Internet 326 | connection), but the base images for a build as well as all the other 327 | package requirements your build will need, also exist on the local network, this 328 | allows builds for balena devices to still be carried out. 329 | 330 | Another good example is if you have your own CI/CD pipeline with dedicated 331 | machines that cache specific package/build data that you use frequently. In 332 | these cases, a build on a local machine may be significantly quicker than 333 | using balena generic builders. 334 | 335 | Before we try building locally, it's worth a note on an extra switch that can be 336 | used with `balena build`. `--emulated` tells balena CLI that the target 337 | architecture environment should be emulated, if it differs from that of the 338 | native architecture on which balena CLI is being run. For example, most 339 | development machines tend to use an x64 architecture, whereas a large number of 340 | devices are based around Armv6 or v7 (and more lately v8) architectures. To 341 | correctly build images for Arm targets, an x64 builder must emulate the target 342 | architecture whilst running the Docker commands. Because we're assuming the use 343 | of a balenaFin here, we'll run all local builds using the `--emulated` switch. 344 | Should you be building for an Intel NUC, or other AMD64 based device, you do not 345 | need to pass this switch in the following examples. 346 | 347 | To carry out a local build requires more information than a `balena push`, 348 | because balena CLI needs to know the CPU architecture and device type to produce 349 | a Docker image that will work on the specified target. The easiest way to do 350 | this is to specify a fleet, which will allow balena CLI to determine this 351 | information itself by querying the balenaCloud API. In the 352 | `balena-cli-masterclass` repository, execute this command: 353 | 354 | ```shell 355 | $ balena build --fleet cliFleet --emulated 356 | [Info] Creating default composition with source: /Work/Support/MasterClasses/repos/balena-cli-masterclass 357 | [Info] Building for armv7hf/fincm3 358 | [Info] Emulation is enabled 359 | [Build] Built 1 service in 1:32 360 | [Build] main Image size: 208.45 MB 361 | ``` 362 | 363 | A call to `docker images` will show the newly built image: 364 | 365 | ```shell 366 | $ docker images 367 | REPOSITORY TAG IMAGE ID CREATED SIZE 368 | balena-cli-masterclass_main latest 321025486d49 About a minute ago 219MB 369 | ``` 370 | 371 | As mentioned, there are instances where the ability to use balenaCloud is not 372 | possible (for example an air-gapped network), or is not desirable. In these 373 | situations, `balena build` can be notified of the device type and architecture 374 | to build on the command line. To get the architecture of each supported device, 375 | execute this command: 376 | 377 | ``` 378 | balena devices supported -v 379 | ``` 380 | 381 | Once you know the architecture and device type of the device you want to emulate, 382 | execute this command to start building: 383 | 384 | ```shell 385 | $ balena build --arch armv7hf --deviceType fincm3 --emulated 386 | [Info] Creating default composition with source: /Work/Support/MasterClasses/repos/balena-cli-masterclass 387 | [Info] Building for armv7hf/fincm3 388 | [Info] Emulation is enabled 389 | [Build] Built 1 service in 1:41 390 | [Build] main Image size: 219.15 MB 391 | [Success] Build succeeded! 392 | ``` 393 | 394 | There are a few caveats to building images locally, however. Emulated builds 395 | will always be slower than native builds due to having to mimic a different 396 | architecture. Coupled with other factors, such as potentially lower 397 | network bandwidth than that enjoyed by the balenaCloud builders, this can 398 | mean a far slower build than would occur than pushing to our native builders 399 | (which use both dedicated 64bit AMD64 and Arm servers). 400 | 401 | #### 5.2 Deploying an Image from a Development Machine 402 | 403 | An image from a development machine can be deployed as a fleet release 404 | to balenaCloud from balena CLI. This allows any pre-built image to be uploaded 405 | directly to balena's registry without the requirement of the builder to 406 | generate it first. Assuming you've followed exercise 5.1, run the following: 407 | 408 | ```shell 409 | $ balena deploy cliFleet balena-cli-masterclass_main:latest 410 | [Info] Creating default composition with image: balena-cli-masterclass_main:latest 411 | [Info] Everything is up to date (use --build to force a rebuild) 412 | [Info] Creating release... 413 | [Info] Pushing images to registry... 414 | [Info] Saving release... 415 | [Success] Deploy succeeded! 416 | [Success] Release: b9e5ec4b309f91281ecb592028dcea0c 417 | 418 | \ 419 | \ 420 | \\ 421 | \\ 422 | >\/7 423 | _.-(6' \ 424 | (=___._/` \ 425 | ) \ | 426 | / / | 427 | / > / 428 | j < _\ 429 | _.-' : ``. 430 | \ r=._\ `. 431 | <`\\_ \ .`-. 432 | \ r-7 `-. ._ ' . `\ 433 | \`, `-.`7 7) ) 434 | \/ \| \' / `-._ 435 | || .' 436 | \\ ( 437 | >\ > 438 | ,.-' >.' 439 | <.'_.'' 440 | <' 441 | ``` 442 | 443 | This will create a new release (visible via the dashboard), and push the image 444 | directly to the balena Docker registry. Your balenaFin should then download the 445 | new release and run it. This is useful if you already have an image pre-built 446 | and just need to upload it. 447 | 448 | However, `balena deploy` also allows you to complete the build step as well 449 | implicitly by not specifying an image to upload. Run the following command in 450 | the `balena-cli-masterclass` repository: 451 | 452 | ```shell 453 | $ balena deploy cliFleet --build --emulated 454 | [Info] Creating default composition with source: /Work/Support/MasterClasses/repos/balena-cli-masterclass 455 | [Info] Building for armv7hf/fincm3 456 | [Build] Built 1 service in 0:58 457 | [Build] main Image size: 213.80 MB 458 | [Info] Creating release... 459 | [Info] Pushing images to registry... 460 | [Info] Saving release... 461 | [Success] Deploy succeeded! 462 | [Success] Release: 13f39923c2ddf95fa35a129d8efb5b53 463 | 464 | \ 465 | \ 466 | \\ 467 | \\ 468 | >\/7 469 | _.-(6' \ 470 | (=___._/` \ 471 | ) \ | 472 | / / | 473 | / > / 474 | j < _\ 475 | _.-' : ``. 476 | \ r=._\ `. 477 | <`\\_ \ .`-. 478 | \ r-7 `-. ._ ' . `\ 479 | \`, `-.`7 7) ) 480 | \/ \| \' / `-._ 481 | || .' 482 | \\ ( 483 | >\ > 484 | ,.-' >.' 485 | <.'_.'' 486 | <' 487 | ``` 488 | 489 | This forces the `deploy` command to first build (or rebuild if the image already 490 | exists) the project before pushing it to the Docker registries. 491 | 492 | ### 6. Using Local Mode to Develop your Application 493 | 494 | So far, you've seen how to push code to the balena builders or to build and 495 | push images on a development machine. Whilst practical solutions for pre-tested 496 | code, or for a CI pipeline, this is not a fast workflow for active development 497 | of an app by an engineer as it involves rebuilding an image and then 498 | delivering it to the target device. 499 | 500 | To make active development of app easier for an engineer, balena 501 | devices provisioned with a development image include a device mechanism called 502 | 'Local Mode'. This can be activated easily from the dashboard. Go to your 503 | device's dashboard page, select 'Settings' from the lefthand toolbar, and then 504 | select 'Local mode'. Local mode does a couple of important things: 505 | 506 | * Stops running the services currently associated with the device 507 | * Exposes a Docker socket on the local network 508 | 509 | Once activated, balena CLI can push code directly to the local device instead 510 | of going via the balena builders. Code is built on the device and then executed, 511 | which can significantly speed up development when requiring frequent changes. 512 | As mentioned previously, you can find local devices on your network in 513 | development mode by using `balena device detect`. 514 | 515 | `balena push` includes optional switches which allow you to specify that you 516 | want to push code to a local device using the results from `balena device detect`. 517 | To see this working in practice, carry out a `balena device detect`, and then pass either 518 | the host or IP address to `balena push` whilst in the `balena-cli-masterclass` 519 | repository: 520 | 521 | ```shell 522 | $ balena push 827b231.local 523 | [Info] Starting build on device 827b231.local 524 | [Info] Creating default composition with source: . 525 | [Build] [main] Step 1/8 : FROM balenalib/fincm3-node:8 526 | [Build] [main] ---> 392c3f6339f7 527 | [Build] [main] Step 2/8 : WORKDIR /usr/src/app 528 | [Build] [main] ---> Running in 446517b1afdb 529 | [Build] [main] Removing intermediate container 446517b1afdb 530 | [Build] [main] ---> c27a2f22ba27 531 | [Build] [main] Step 3/8 : COPY package.json package-lock.json ./ 532 | [Build] [main] ---> fc79948ab18b 533 | [Build] [main] Step 4/8 : RUN npm install --ci --production && npm cache clean --force && rm -f /tmp/* 534 | [Build] [main] ---> Running in 59c1b1cbe571 535 | [Build] [main] added 50 packages from 37 contributors and audited 126 packages in 9.178s 536 | [Build] [main] found 0 vulnerabilities 537 | [Build] [main] npm 538 | [Build] [main] 539 | [Build] [main] WARN 540 | [Build] [main] 541 | [Build] [main] using --force 542 | [Build] [main] I sure hope you know what you are doing. 543 | [Build] 544 | [Build] [main] Removing intermediate container 59c1b1cbe571 545 | [Build] [main] ---> 0cdc6d1d7af9 546 | [Build] [main] Step 5/8 : COPY src/ ./src/ 547 | [Build] [main] ---> 23e41b46ee6f 548 | [Build] [main] Step 6/8 : CMD ["npm", "start"] 549 | [Build] [main] ---> Running in c62943c5e22f 550 | [Build] [main] Removing intermediate container c62943c5e22f 551 | [Build] [main] ---> 9434eb22cc67 552 | [Build] [main] Step 7/8 : LABEL io.resin.local.image=1 553 | [Build] [main] ---> Running in 9023bae27f0f 554 | [Build] [main] Removing intermediate container 9023bae27f0f 555 | [Build] [main] ---> 7e2603a523f2 556 | [Build] [main] Step 8/8 : LABEL io.resin.local.service=main 557 | [Build] [main] ---> Running in 05feac72072e 558 | [Build] [main] Removing intermediate container 05feac72072e 559 | [Build] [main] ---> 9ef9a4510175 560 | [Build] [main] Successfully built 9ef9a4510175 561 | [Build] [main] Successfully tagged local_image_main:latest 562 | 563 | [Info] Streaming device logs... 564 | [Live] Watching for file changes... 565 | [Live] Waiting for device state to settle... 566 | [Logs] [9/5/2019, 2:34:37 PM] Creating network 'default' 567 | [Logs] [9/5/2019, 2:34:37 PM] Creating volume 'resin-data' 568 | [Logs] [9/5/2019, 2:34:37 PM] Installing service 'main sha256:9ef9a45101757ee81aa26d5ca43713289b2e99401d1b13e32842523876fde664' 569 | [Logs] [9/5/2019, 2:34:38 PM] Installed service 'main sha256:9ef9a45101757ee81aa26d5ca43713289b2e99401d1b13e32842523876fde664' 570 | [Logs] [9/5/2019, 2:34:38 PM] Starting service 'main sha256:9ef9a45101757ee81aa26d5ca43713289b2e99401d1b13e32842523876fde664' 571 | [Logs] [9/5/2019, 2:34:39 PM] Started service 'main sha256:9ef9a45101757ee81aa26d5ca43713289b2e99401d1b13e32842523876fde664' 572 | [Live] Device state settled 573 | [Logs] [9/5/2019, 2:34:41 PM] [main] 574 | [Logs] [9/5/2019, 2:34:41 PM] [main] > balena-cli-masterclass@1.0.0 start /usr/src/app 575 | [Logs] [9/5/2019, 2:34:41 PM] [main] > node src/helloworld.js; sleep infinity 576 | [Logs] [9/5/2019, 2:34:41 PM] [main] 577 | [Logs] [9/5/2019, 2:34:41 PM] [main] Hello world! 578 | ``` 579 | 580 | Once the code has been built on the device, it immediately starts executing 581 | and logs are output to the console. You can halt the connection to the local 582 | device by using `Ctrl-C`. Note that after disconnection, the service containers 583 | on the device will continue to run. 584 | 585 | In a multi-container environment, it may quickly become difficult for an engineer 586 | to determine whether their code is working, especially if many services are 587 | all outputting log information. In these cases, filtering log output via 588 | service is possible, by using the `--service` switch (we've also used the 589 | `--nocache` option here to force a rebuild and restart, else we wouldn't see any 590 | other logs as the service wouldn't have changed): 591 | 592 | ```shell 593 | $ balena push 827b231.local --service main --nocache 594 | [Info] Starting build on device 827b231.local 595 | [Info] Creating default composition with source: . 596 | [Build] [main] Step 1/8 : FROM balenalib/fincm3-node:8 597 | [Build] [main] ---> 392c3f6339f7 598 | [Build] [main] Step 2/8 : WORKDIR /usr/src/app 599 | [Build] [main] ---> Using cache 600 | [Build] [main] ---> c27a2f22ba27 601 | [Build] [main] Step 3/8 : COPY package.json package-lock.json ./ 602 | [Build] [main] ---> Using cache 603 | [Build] [main] ---> fc79948ab18b 604 | [Build] [main] Step 4/8 : RUN npm install --ci --production && npm cache clean --force && rm -f /tmp/* 605 | [Build] [main] ---> Using cache 606 | [Build] [main] ---> 0cdc6d1d7af9 607 | [Build] [main] Step 5/8 : COPY src/ ./src/ 608 | [Build] [main] ---> 5adcd43b12c6 609 | [Build] [main] Step 6/8 : CMD ["npm", "start"] 610 | [Build] [main] ---> Running in a415b6e7f0af 611 | [Build] [main] Removing intermediate container a415b6e7f0af 612 | [Build] [main] ---> 1a1ff3926d42 613 | [Build] [main] Step 7/8 : LABEL io.resin.local.image=1 614 | [Build] [main] ---> Running in 7390bcd46425 615 | [Build] [main] Removing intermediate container 7390bcd46425 616 | [Build] [main] ---> ebf9fc9c43ed 617 | [Build] [main] Step 8/8 : LABEL io.resin.local.service=main 618 | [Build] [main] ---> Running in 52ab62708a46 619 | [Build] [main] Removing intermediate container 52ab62708a46 620 | [Build] [main] ---> 60f2a99b07c8 621 | [Build] [main] Successfully built 60f2a99b07c8 622 | [Build] [main] Successfully tagged local_image_main:latest 623 | 624 | [Live] Waiting for device state to settle... 625 | [Info] Streaming device logs... 626 | [Live] Watching for file changes... 627 | [Logs] [9/5/2019, 2:46:54 PM] [main] 628 | [Logs] [9/5/2019, 2:46:54 PM] [main] > balena-cli-masterclass@1.0.0 start /usr/src/app 629 | [Logs] [9/5/2019, 2:46:54 PM] [main] > node src/helloworld.js; sleep infinity 630 | [Logs] [9/5/2019, 2:46:54 PM] [main] 631 | [Logs] [9/5/2019, 2:46:54 PM] [main] Hello world! 632 | ``` 633 | 634 | As you can see, none of the Supervisor logs were printed. Note that there is 635 | also a `balena device logs` command that is dedicated to just showing logs. This 636 | command includes both the `--system` and `--service` switches to filter 637 | output to just that of system messages or particular service messages (these 638 | switches can be combined in a single `balena device logs` call). This allows the 639 | setup of multiple terminals to act as loggers whilst another is used to 640 | carry out `balena push` executions. A few examples of logging are shown below: 641 | 642 | * `balena device logs 827b231.local --system --service main` - Will output all 643 | system messages and those from the `main` service 644 | * `balena device logs 827b231.local --service main` will only output messages from 645 | the `main` service 646 | * `balena device logs 827b231.local --service main --service secondary` will only 647 | output messages from the `main` and `secondary` services 648 | 649 | Local Mode also has another huge benefit, known as Livepush. 650 | [Livepush](https://github.com/balena-io-modules/livepush) makes intelligent 651 | decisions on how, or even if, to rebuild an image when changes are made. It 652 | does this by examining the source directory of an image being built on your 653 | local development machine (via balena CLI) and then deciding how to deal with 654 | changes. 655 | 656 | In some cases, Livepush rebuilds relevant parts of the image before starting the 657 | new image as the service. As an example of this, ensure you've executed 658 | `balena push` in Local Mode: 659 | 660 | ```shell 661 | $ balena push 827b231.local --service main 662 | ``` 663 | 664 | Now modify `Dockerfile.template` in the `balena-cli-masterclass` repository in a 665 | text editor, inserting a new line between the `COPY src/ ./src/` command and 666 | `CMD ["npm", "start"]`: 667 | 668 | ```shell 669 | ... 670 | COPY src/ ./src/ 671 | 672 | RUN echo "Rebuild the image" 673 | 674 | CMD ["npm", "start"] 675 | ``` 676 | 677 | Finally, save the changes to the file in your text editor. The Supervisor 678 | will immediately detect that the Dockerfile has changed and will start a rebuild 679 | of the service: 680 | 681 | ```shell 682 | [Live] Detected Dockerfile change, performing full rebuild of service main 683 | [Build] [main] Step 1/9 : FROM balenalib/fincm3-node:8 684 | [Build] [main] ---> 392c3f6339f7 685 | [Build] [main] Step 2/9 : WORKDIR /usr/src/app 686 | [Build] [main] ---> Using cache 687 | [Build] [main] ---> c27a2f22ba27 688 | [Build] [main] Step 3/9 : COPY package.json package-lock.json ./ 689 | [Build] [main] ---> Using cache 690 | [Build] [main] ---> fc79948ab18b 691 | [Build] [main] Step 4/9 : RUN npm install --ci --production && npm cache clean --force && rm -f /tmp/* 692 | [Build] [main] ---> Using cache 693 | [Build] [main] ---> 0cdc6d1d7af9 694 | [Build] [main] Step 5/9 : COPY src/ ./src/ 695 | [Build] [main] ---> fec02483c800 696 | [Build] [main] Step 6/9 : RUN echo "Rebuild the image" 697 | [Build] [main] ---> Running in 0c1f2cbca19f 698 | [Build] [main] Rebuild the image 699 | [Build] [main] Removing intermediate container 0c1f2cbca19f 700 | [Build] [main] ---> aec92835242c 701 | [Build] [main] Step 7/9 : CMD ["npm", "start"] 702 | [Build] [main] ---> Running in 824e56df2920 703 | [Build] [main] Removing intermediate container 824e56df2920 704 | [Build] [main] ---> c49d013039de 705 | [Build] [main] Step 8/9 : LABEL io.resin.local.image=1 706 | [Build] [main] ---> Running in e9158ba83571 707 | [Build] [main] Removing intermediate container e9158ba83571 708 | [Build] [main] ---> 2317085d9161 709 | [Build] [main] Step 9/9 : LABEL io.resin.local.service=main 710 | [Build] [main] ---> Running in ebcaf1a3351d 711 | [Build] [main] Removing intermediate container ebcaf1a3351d 712 | [Build] [main] ---> fc5e4459c406 713 | [Build] [main] Successfully built fc5e4459c406 714 | [Build] [main] Successfully tagged local_image_main:latest 715 | [Logs] [9/5/2019, 3:58:56 PM] [main] 716 | [Logs] [9/5/2019, 3:58:56 PM] [main] > balena-cli-masterclass@1.0.0 start /usr/src/app 717 | [Logs] [9/5/2019, 3:58:56 PM] [main] > node src/helloworld.js; sleep infinity 718 | [Logs] [9/5/2019, 3:58:56 PM] [main] 719 | [Logs] [9/5/2019, 3:58:56 PM] [main] Hello world! 720 | ``` 721 | 722 | Once rebuilt, it will restart the service. Notice that the `Rebuild the image` 723 | echoed line is now in the build log. 724 | 725 | Livepush goes way further than this, however. Only files that affect the 726 | building of the service force a rebuild. For other files, for example source 727 | files that run in-service, the Supervisor replaces the files in-situ in the 728 | relevant container layer. 729 | To show this, continue to run the `balena push` command and then alter the 730 | `src/helloworld.js` in a text editor and change: 731 | 732 | ```shell 733 | console.log('Hello world!'); 734 | ``` 735 | 736 | to 737 | 738 | ```shell 739 | console.log('Hello moon!'); 740 | ``` 741 | 742 | On saving the file, you'll see the following output: 743 | 744 | ```shell 745 | [Live] Detected changes for container main, updating... 746 | [Live] [main] Restarting service... 747 | [Logs] [9/5/2019, 4:02:27 PM] [main] 748 | [Logs] [9/5/2019, 4:02:27 PM] [main] > balena-cli-masterclass@1.0.0 start /usr/src/app 749 | [Logs] [9/5/2019, 4:02:27 PM] [main] > node src/helloworld.js; sleep infinity 750 | [Logs] [9/5/2019, 4:02:27 PM] [main] 751 | [Logs] [9/5/2019, 4:02:28 PM] [main] Hello moon! 752 | ``` 753 | 754 | Instead of rebuilding the image, which takes time, the file is injected directly 755 | into the container's file system and then it is restarted. This happens in a 756 | few seconds and makes the process of developing much faster and more convenient. 757 | 758 | Sometimes an engineer may not want to rebuild code 'on the fly'. For this reason 759 | `balena push` in Local Mode also has a `--nolive` option which can be passed 760 | to it. When using this switch, engineers need to re`push` when they want to 761 | rebuild code. 762 | 763 | Livepush also supports `balena device logs`, and can be used in the same way as 764 | described earlier. 765 | 766 | ### 7. Using Private Registries 767 | 768 | As well as using public Docker registries it's possible to instruct builders, 769 | either balena-based or using Local Mode, to pull images from private Docker 770 | registries. This is achieved by using the `--registry-secrets` switch when 771 | calling `balena push` passing a filename containing the secret information. 772 | This information can be in either YAML or JSON. For example, a relevant 773 | JSON object containing this information follows: 774 | 775 | ```json 776 | { 777 | "https://index.docker.io/v1/": { 778 | "username": "myUser", 779 | "password": "myPassword" 780 | } 781 | } 782 | ``` 783 | 784 | If saved as a JSON file, for example `secrets.json`, it will then be used when 785 | a base image or image for a service is pulled which requires credentials: 786 | 787 | ```shell 788 | $ balena push --registry-secrets secrets.json 789 | ``` 790 | 791 | You can also save a file with secrets in JSON or YAML format in your home 792 | directory, under `~/.balena/secrets.`, which will automatically be 793 | used for the secrets if it exists and the `--registry-secrets` switch has not 794 | been passed to `balena push`. 795 | 796 | ### 8. Building with Secrets and Variables 797 | 798 | Building images occasionally requires the use of credentials (such as those 799 | for private repositories), or environment variables that may change depending 800 | on circumstances such as architecture (for example package versioning). 801 | 802 | The following exercise sections show you how to use build-time secrets and 803 | variable substitution. 804 | 805 | #### 8.1 Build Time Secrets 806 | 807 | Sometimes it is necessary to build images using secret information, commonly 808 | to login to source repositories or fetch data that is required for the building 809 | of an image, but which should not exist *in* that image when run as a service 810 | container. 811 | 812 | Our builders allow you to do this by adding such secrets in files in a 813 | `.balena` directory in the root of the build directory. This allows them to 814 | be passed to builders, which will use (and then discard) them for generating 815 | images. 816 | 817 | We'll make a few changes to the example project to show this in operation. 818 | First, create a `.balena` directory in the root of the `balena-cli-masterclass` 819 | directory, and then create an empty `balena.yml` file and create another 820 | directory called `secrets` in the `.balena` directory. You should now have a 821 | file tree that looks like this: 822 | 823 | ```shell 824 | $ tree -a -I .git 825 | . 826 | ├── .balena 827 | │   ├── balena.yml 828 | │   └── secrets 829 | ├── Dockerfile.template 830 | ├── README.md 831 | ├── package-lock.json 832 | ├── package.json 833 | └── src 834 | └── helloworld.js 835 | ``` 836 | 837 | You can now add secrets to the build by adding a section to the `balena.yml` 838 | file and then creating appropriate secret files in the `.balena/secrets` 839 | directory. We'll add some now, open a text editor and fill the `balena.yml` 840 | file with the following: 841 | 842 | ```yaml 843 | build-secrets: 844 | global: 845 | - source: my-build-secrets 846 | dest: my-secrets 847 | ``` 848 | 849 | Note that the source file should exist in the `.balena/secrets` directory, and 850 | that it is mapped into the `my-secrets` file when the image is built. 851 | Save the file, and create a new one called `.balena/secrets/my-build-secrets` 852 | and copy the following into it: 853 | 854 | ```shell 855 | This file has build-time secrets! 856 | ``` 857 | 858 | Finally, we'll add a line into our Dockerfile that uses the secrets file, which 859 | is mapped into the `/run/secrets/` directory during build time: 860 | 861 | ```shell 862 | COPY src/ ./src/ 863 | 864 | RUN cat /run/secrets/my-secrets 865 | 866 | CMD ["npm", "start"] 867 | ``` 868 | 869 | Now, push the project to the builders: 870 | 871 | ```shell 872 | $ balena push cliFleet 873 | [Info] Starting build for cliFleet, user heds 874 | [Info] Dashboard link: https://dashboard.balena-cloud.com/apps/1505952/devices 875 | [Info] Building on arm03 876 | [Info] Pulling previous images for caching purposes... 877 | [Success] Successfully pulled cache images 878 | [main] Step 1/7 : FROM balenalib/fincm3-node:8 879 | [main] ---> 392c3f6339f7 880 | [main] Step 2/7 : WORKDIR /usr/src/app 881 | [main] ---> f9c421b7aa77 882 | [main] Removing intermediate container df598a62ef2c 883 | [main] Step 3/7 : COPY package.json package-lock.json ./ 884 | [main] ---> 6af34973ecb0 885 | [main] Removing intermediate container d7b84160d116 886 | [main] Step 4/7 : RUN npm install --ci --production && npm cache clean --force && rm -f /tmp/* 887 | [main] ---> Running in e0a52c6e7d2e 888 | [main] added 50 packages from 37 contributors and audited 126 packages in 2.53s 889 | [main] found 0 vulnerabilities 890 | [main] npm 891 | [main] WARN using --force 892 | [main] I sure hope you know what you are doing. 893 | [main] 894 | [main] ---> 9ff0e005febd 895 | [main] Removing intermediate container e0a52c6e7d2e 896 | [main] Step 5/7 : COPY src/ ./src/ 897 | [main] ---> 211ef0e15576 898 | [main] Removing intermediate container 75e2127552bf 899 | [main] Step 6/7 : RUN cat /run/secrets/my-secrets 900 | [main] ---> Running in 949098cba8b6 901 | [main] This file has build-time secrets! 902 | [main] ---> 6da25ec8f94f 903 | [main] Removing intermediate container 949098cba8b6 904 | [main] Step 7/7 : CMD npm start 905 | [main] ---> Running in 1ae564a36e44 906 | [main] ---> e590faac0013 907 | [main] Removing intermediate container 1ae564a36e44 908 | [main] Successfully built e590faac0013 909 | [Info] Uploading images 910 | [Success] Successfully uploaded images 911 | [Info] Built on arm03 912 | [Success] Release successfully created! 913 | [Info] Release: cedeff39dc537c9cd4c1df3b97ffcbc7 (id: 1055448) 914 | [Info] ┌─────────┬────────────┬────────────┐ 915 | [Info] │ Service │ Image Size │ Build Time │ 916 | [Info] ├─────────┼────────────┼────────────┤ 917 | [Info] │ main │ 208.47 MB │ 11 seconds │ 918 | [Info] └─────────┴────────────┴────────────┘ 919 | [Info] Build finished in 46 seconds 920 | \ 921 | \ 922 | \\ 923 | \\ 924 | >\/7 925 | _.-(6' \ 926 | (=___._/` \ 927 | ) \ | 928 | / / | 929 | / > / 930 | j < _\ 931 | _.-' : ``. 932 | \ r=._\ `. 933 | <`\\_ \ .`-. 934 | \ r-7 `-. ._ ' . `\ 935 | \`, `-.`7 7) ) 936 | \/ \| \' / `-._ 937 | || .' 938 | \\ ( 939 | >\ > 940 | ,.-' >.' 941 | <.'_.'' 942 | <' 943 | ``` 944 | 945 | As you can see, step 6 output: 946 | 947 | ```shell 948 | [main] Step 6/7 : RUN cat /run/secrets/my-secrets 949 | [main] ---> Running in 949098cba8b6 950 | [main] This file has build-time secrets! 951 | ``` 952 | 953 | which is the contents of the secrets file. This file could obviously contain 954 | a raft of different functions, including a script that gets executed, text 955 | for filling in files, etc. As well as defining globally accessible secrets 956 | (which are shared to all services being built), there is also the option to 957 | define secrets that are only accessible to particular services, or to map them 958 | to different paths. This becomes useful in multi-container build scenarios. This 959 | can be achieved by appending a `services` section to `build-secrets` on the 960 | `balena.yml` file. For example: 961 | 962 | ```yaml 963 | build-secrets: 964 | services: 965 | main: 966 | - source: main-only-secrets 967 | dest: my-main-secrets 968 | ``` 969 | 970 | This change would map the `.balena/secrets/main-only-secrets` file into the 971 | `/run/secrets/my-main-secrets` runtime path at build-time but *only for the 972 | `main` service*. 973 | 974 | #### 8.2 Build Time Variables 975 | 976 | Another frequent build-time use is that of environment variables that may alter 977 | between builds but still use the same flow of a Dockerfile. Allowing these to 978 | be defined dynamically means that no changes to a Dockerfile are required as 979 | long as the variables are referenced within them. 980 | 981 | Much in a similar way to secrets files, these are defined in the 982 | `.balena/balena.yml` file. Add two new build-time arguments to your 983 | `balena.yml` file: 984 | 985 | ```yaml 986 | build-variables: 987 | global: 988 | - BUILD_TIME_ARG_1=This is the first arg 989 | - BUILD_TIME_ARG_2=This is the second arg 990 | ``` 991 | 992 | Now alter the Dockerfile to use them: 993 | 994 | ```Dockerfile 995 | RUN cat /run/secrets/my-secrets 996 | 997 | ARG BUILD_TIME_ARG_1 998 | ARG BUILD_TIME_ARG_2 999 | 1000 | RUN echo "${BUILD_TIME_ARG_1}" && \ 1001 | echo "${BUILD_TIME_ARG_2}" 1002 | 1003 | CMD ["npm", "start"] 1004 | ``` 1005 | 1006 | Note that you need to ensure that both arguments are declared using the `ARG` 1007 | Docker command. Save the file and push to the builders: 1008 | 1009 | ```shell 1010 | $ balena push cliFleet --nocache 1011 | [Info] Starting build for cliFleet, user heds 1012 | [Info] Dashboard link: https://dashboard.balena-cloud.com/apps/1505952/devices 1013 | [Info] Building on arm01 1014 | [Info] Pulling previous images for caching purposes... 1015 | [Success] Successfully pulled cache images 1016 | [main] Step 1/10 : FROM balenalib/fincm3-node:8 1017 | [main] ---> 392c3f6339f7 1018 | [main] Step 2/10 : WORKDIR /usr/src/app 1019 | [main] ---> 0d930a93f967 1020 | [main] Removing intermediate container 37dcff73ed1b 1021 | [main] Step 3/10 : COPY package.json package-lock.json ./ 1022 | [main] ---> 036c9574af90 1023 | [main] Removing intermediate container 19b7f4d28593 1024 | [main] Step 4/10 : RUN npm install --ci --production && npm cache clean --force && rm -f /tmp/* 1025 | [main] ---> Running in fa65ea126c2d 1026 | [main] added 50 packages from 37 contributors and audited 126 packages in 2.436s 1027 | [main] found 0 vulnerabilities 1028 | [main] npm 1029 | [main] WARN using --force I sure hope you know what you are doing. 1030 | [main] 1031 | [main] ---> 6369ab6a6802 1032 | [main] Removing intermediate container fa65ea126c2d 1033 | [main] Step 5/10 : COPY src/ ./src/ 1034 | [main] ---> a7103d76c564 1035 | [main] Removing intermediate container ae6e3614de1d 1036 | [main] Step 6/10 : RUN cat /run/secrets/my-secrets 1037 | [main] ---> Running in 3bc6e36ce8d1 1038 | [main] This file has build-time secrets! 1039 | [main] ---> 6ee5058cc5f3 1040 | [main] Removing intermediate container 3bc6e36ce8d1 1041 | [main] Step 7/10 : ARG BUILD_TIME_ARG_1 1042 | [main] ---> Running in a42ba6af90d6 1043 | [main] ---> 06bd854b2e68 1044 | [main] Removing intermediate container a42ba6af90d6 1045 | [main] Step 8/10 : ARG BUILD_TIME_ARG_2 1046 | [main] ---> Running in dcc256fdc0a6 1047 | [main] ---> e283099d8adc 1048 | [main] Removing intermediate container dcc256fdc0a6 1049 | [main] Step 9/10 : RUN echo "${BUILD_TIME_ARG_1}" && echo "${BUILD_TIME_ARG_2}" 1050 | [main] ---> Running in 1c572bc0e7c0 1051 | [main] This is the first arg 1052 | [main] This is the second arg 1053 | [main] ---> 81c8da87d775 1054 | [main] Removing intermediate container 1c572bc0e7c0 1055 | [main] Step 10/10 : CMD npm start 1056 | [main] ---> Running in 81dd184fc8ee 1057 | [main] ---> d494a4090d2d 1058 | [main] Removing intermediate container 81dd184fc8ee 1059 | [main] Successfully built d494a4090d2d 1060 | [Info] Uploading images 1061 | [Success] Successfully uploaded images 1062 | [Info] Built on arm01 1063 | [Success] Release successfully created! 1064 | [Info] Release: 7efbc95825641b6482742a54c8e74010 (id: 1056307) 1065 | [Info] ┌─────────┬────────────┬────────────┐ 1066 | [Info] │ Service │ Image Size │ Build Time │ 1067 | [Info] ├─────────┼────────────┼────────────┤ 1068 | [Info] │ main │ 208.48 MB │ 9 seconds │ 1069 | [Info] └─────────┴────────────┴────────────┘ 1070 | [Info] Build finished in 28 seconds 1071 | \ 1072 | \ 1073 | \\ 1074 | \\ 1075 | >\/7 1076 | _.-(6' \ 1077 | (=___._/` \ 1078 | ) \ | 1079 | / / | 1080 | / > / 1081 | j < _\ 1082 | _.-' : ``. 1083 | \ r=._\ `. 1084 | <`\\_ \ .`-. 1085 | \ r-7 `-. ._ ' . `\ 1086 | \`, `-.`7 7) ) 1087 | \/ \| \' / `-._ 1088 | || .' 1089 | \\ ( 1090 | >\ > 1091 | ,.-' >.' 1092 | <.'_.'' 1093 | <' 1094 | ``` 1095 | 1096 | As can be seen, both build arguments were available in the log output: 1097 | 1098 | ```shell 1099 | [main] This is the first arg 1100 | [main] This is the second arg 1101 | ``` 1102 | 1103 | In the same way that build secrets can be made service specific, so may secret 1104 | build arguments, by specifying them directly in the `.balena/balena.yml` file: 1105 | 1106 | ```yaml 1107 | build-variables: 1108 | services: 1109 | main: 1110 | - MAIN_ONLY_BUILD_ARG=This is only available when building 'main' 1111 | ``` 1112 | 1113 | An important note for build variables is that, unlike secrets, they will be 1114 | defined and available as part of the final image. If you need variables to 1115 | be secret, they should be defined specifically as secrets. 1116 | 1117 | ## Conclusion 1118 | 1119 | In this masterclass, you've learned how to use the most commonly used balena CLI 1120 | commands, as well as how to start development using it. You should now be 1121 | familiar and confident enough to: 1122 | 1123 | * Create fleets for specific device types 1124 | * Provision devices as well as SSH into balenaOS and any running service 1125 | container 1126 | * Push a release to fleets, either via `balena push` or `git push` 1127 | * Locally build service images on a development machine, as well as deploying 1128 | those images to balenaCloud 1129 | * Switch a development device into Local Mode, push code locally to a device 1130 | to build, and debug the app faster. 1131 | * Use Livepush to dynamically alter the app code on the fly and immediately 1132 | see results on a device in Local Mode, as well as filter log output for 1133 | specific services in the app. 1134 | * Use build secret files and arguments to generate images which 1135 | should not include those secrets, as well as build variables 1136 | 1137 | ## References 1138 | 1139 | None 1140 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "balena-cli-masterclass", 3 | "version": "1.1.12", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "balena-cli-masterclass", 3 | "version": "1.1.12", 4 | "description": "balenaCLI masterclass application", 5 | "main": "src/helloworld.js", 6 | "scripts": { 7 | "start": "node src/helloworld.js; sleep infinity", 8 | "test": "echo \"There are no tests for this repository\" && exit 0" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+ssh://git@github.com/balena-io/balena-cli-masterclass.git" 13 | }, 14 | "author": "Heds Simons ", 15 | "license": "Apache-2.0", 16 | "bugs": { 17 | "url": "https://github.com/balena-io/balena-cli-masterclass/issues" 18 | }, 19 | "homepage": "https://github.com/balena-io/balena-cli-masterclass#readme", 20 | "private": true, 21 | "versionist": { 22 | "publishedAt": "2025-02-07T13:05:03.433Z" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/helloworld.js: -------------------------------------------------------------------------------- 1 | console.log('Hello world!'); 2 | --------------------------------------------------------------------------------