ODO 与 Rancher Desktop

odo 是一款快速、迭代开发且简单的 CLI 工具,适合在 Kubernetes 上编写、构建和部署应用程序的开发人员。odo CLI 抽象出了复杂的 Kubernetes 概念,让开发人员能够专注于代码迭代。该工具可以检测本地代码的更改,并将其自动部署到容器编排的集群中,通过即时反馈来实时验证更改。有关更多信息,请参阅 odo 项目文档

前提

在本指南中,你将使用 Rancher Desktop 文档仓库中的 express-sample node.js 应用程序来学习如何使用 odo 和 Rancher Desktop。

ODO 与 Rancher Desktop - 图1备注

ododockerd (moby) 运行时配合使用,请从偏好设置对话框位置中选中它:Preferences > Container Engine > Allowed Images

请确保你的应用程序启用了 Kubernetes。此外,要使用 odo deploy,你需要能够构建镜像并将其推送到 Docker 容器镜像仓库。使用 Docker 凭证登录,如下:

  1. $ docker login docker.io
  2. Username:
  3. Password:
  4. Login Succeeded!

安装

通过 https://odo.dev/docs/overview/installation 安装 odo,并针对你的平台进行安装。该工具既可以用作 CLI 工具,也可以用作 IDE 插件,你还能根据自己的喜好使用其他安装方法。本指南将重点介绍如何通过 CLI 使用该工具。

步骤:odo init

此命令通过创建用于部署的 devfile.yaml 来初始化应用程序。

  1. 克隆 Rancher Desktop 文档仓库,并进入 sample-express 应用程序路径。
  1. git clone https://github.com/rancher-sandbox/docs.rancherdesktop.io.git
  2. cd docs.rancherdesktop.io/assets/express-sample
  1. 在初始化之前,你必须通过命名空间将 odo 连接到集群,该命名空间可以使用 odo create namespace 命令创建:
  1. odo create namespace odo-dev

Details

示例输出

  1. $ odo create namespace odo-dev
  2. Creating the namespace "odo-dev" [5ms]
  3. Namespace "odo-dev" is ready for use
  4. New namespace created and now using namespace: odo-dev
  1. odo init 命令将自动检测你的项目框架,并选择合适的 devfile.yaml 来部署你的应用程序。该命令将让你确认 Devfile (Y/n)、选择容器来更改配置(在本示例中选择 none),然后输入组件名称(例如 my-nodejs-app)。

你也可以使用以下带有附加标志(例如 --devfile-version 2.2.0)的命令来初始化 odo,并允许应用部署:

  1. odo init --name my-nodejs-app --devfile nodejs --devfile-registry DefaultDevfileRegistry --devfile-version 2.2.0

Details

示例输出

  1. __
  2. / \__ Initializing a new component
  3. \__/ \
  4. / \__/ odo version: v3.13.0
  5. \__/
  6. Downloading devfile "nodejs:2.2.0" from registry "DefaultDevfileRegistry" [1s]
  7. Your new component 'my-nodejs-app' is ready in the current directory.
  8. To start editing your component, use 'odo dev' and open this folder in your favorite IDE.
  9. Changes will be directly reflected on the cluster.
  1. odo init

Details

示例输出

  1. $ odo init
  2. __
  3. / \__ Initializing a new component
  4. \__/ \ Files: Source code detected, a Devfile will be determined based upon source code autodetection
  5. / \__/ odo version: v3.13.0
  6. \__/
  7. Interactive mode enabled, please answer the following questions:
  8. Determining a Devfile for the current directory [910ms]
  9. Based on the files in the current directory odo detected
  10. Language: JavaScript
  11. Project type: Node.js
  12. Application ports: 3000
  13. The devfile "nodejs:2.1.1" from the registry "DefaultDevfileRegistry" will be downloaded.
  14. ?Is this correct?Yes
  15. Downloading devfile "nodejs:2.1.1" from registry "DefaultDevfileRegistry" [933ms]
  16. Container Configuration "runtime":
  17. OPEN PORTS:
  18. - 3000
  19. - 5858
  20. ENVIRONMENT VARIABLES:
  21. - DEBUG_PORT = 5858
  22. ?Select container for which you want to change configuration?NONE - configuration is correct
  23. ?Enter component name: my-nodejs-app
  24. You can automate this command by executing:
  25. odo init --name my-nodejs-app --devfile nodejs --devfile-registry DefaultDevfileRegistry --devfile-version 2.1.1
  26. Your new component 'my-nodejs-app' is ready in the current directory.
  27. To start editing your component, use 'odo dev' and open this folder in your favorite IDE.
  28. Changes will be directly reflected on the cluster.

步骤:odo dev

现在,你可以运行 odo dev 命令在通过 IDE 更改代码时持续部署应用程序。

ODO 与 Rancher Desktop - 图2警告

你可能会遇到 ErrImagePull 错误,这是因为该镜像可能未包含在 Rancher Desktop 允许的镜像列表中。要解决该错误,请在 Preferences > Container Engine > Allowed Images 中添加镜像,然后点击 Apply 立即更新允许的镜像列表。

  1. odo dev

Details

示例输出

  1. $ odo dev
  2. __
  3. / \__ Developing using the "my-nodejs-app" Devfile
  4. \__/ \ Namespace: odo-dev
  5. / \__/ odo version: v3.13.0
  6. \__/
  7. Running on the cluster in Dev mode
  8. I0728 13:50:53.115137 92567 starterserver.go:123] API Server started at localhost:20000/api/v1
  9. Waiting for Kubernetes resources ...
  10. Pod is Pending
  11. Pod is Running
  12. Syncing files into the container [306ms]
  13. Building your application in container (command: install) [3s]
  14. Executing the application (command: run) ...
  15. Waiting for the application to be ready [1s]
  16. - Forwarding from 127.0.0.1:20001 -> 3000
  17. Dev mode
  18. Status:
  19. Watching for changes in the current directory /Users/docs.rancherdesktop.io/assets/express-sample
  20. Keyboard Commands:
  21. [Ctrl+c] - Exit and delete resources from the cluster
  22. [p] - Manually apply local changes to the application on the cluster

The express-sample application can now be accessed by the local port (127.0.0.1:20001). As an example, you can make a text change to the index.jade file in the views folder to see a real-time update to the application.

步骤:odo deploy

此命令将根据 devfile.yaml 中的说明将应用程序部署到集群中。

  1. 请务必登录到要推送应用程序的 Docker 容器镜像仓库,并使用 ODO_IMAGE_BUILD_ARGS 环境变量将容器镜像构建参数设置为与容器架构相同:
  • AMD64
  • ARM
  1. export ODO_IMAGE_BUILD_ARGS="--platform=linux/amd64"
  1. export ODO_IMAGE_BUILD_ARGS="--platform=linux/arm64"
  1. 更新 express-sample 目录中的 Dockerfile 以使用正确的变量对应用程序进行容器化,以便构建并推送到镜像仓库:

Details

示例 Dockerfile

  1. # Install the app dependencies in a full SLE Node image
  2. FROM registry.suse.com/bci/nodejs:16
  3. # Copy package.json and package-lock.json
  4. COPY package*.json ./
  5. # Install app dependencies
  6. RUN npm install --production
  7. # Install app dependencies
  8. COPY . /opt/app-root/src
  9. ENV NODE_ENV production
  10. ENV PORT 3000
  11. CMD ["npm", "start"]
  1. 为你的容器集群将 devfile.yaml 修改为下面示例内容。
  • 更新变量以访问容器镜像仓库:
  1. # Add the following variables code anywhere in devfile.yaml
  2. # This MUST be a container registry you are able to access
  3. variables:
  4. CONTAINER_IMAGE: docker.io/<INSERTUSERNAME>/nodejs-odo-example
  5. RESOURCE_NAME: my-nodejs-app
  6. CONTAINER_PORT: "3000"
  7. DOMAIN_NAME: nodejs.example.com
  • 将 Devfile 架构更新为 2.2.0,这是因为 odo deploy 使用此版本。此外,还有一个命令可以使用安装中提到的正确 schemaVersion: 2.2.0 来初始化 odo
  1. # Deploy "kind" ID's use schema 2.2.0+
  2. schemaVersion: 2.2.0
  • 以下命令用于部署活动:

Details

部署命令

  1. # This is the main "composite" command that will run all below commands
  2. commands:
  3. - id: deploy
  4. composite:
  5. commands:
  6. - build-image
  7. - k8s-deployment
  8. - k8s-service
  9. - k8s-url
  10. group:
  11. isDefault: true
  12. kind: deploy
  13. # Below are the commands and their respective components that they are "linked" to deploy
  14. - id: build-image
  15. apply:
  16. component: outerloop-build
  17. - id: k8s-deployment
  18. apply:
  19. component: outerloop-deployment
  20. - id: k8s-service
  21. apply:
  22. component: outerloop-service
  23. - id: k8s-url
  24. apply:
  25. component: outerloop-url
  • 以下命令用于将 Docker 镜像位置、K8s deployment 和 service 添加到组件

Details

组件命令

  1. # This will build the container image before deployment
  2. - name: outerloop-build
  3. image:
  4. dockerfile:
  5. buildContext: ${PROJECT_SOURCE}
  6. rootRequired: false
  7. uri: ./Dockerfile
  8. imageName: "{{CONTAINER_IMAGE}}"
  9. # This will create a Deployment in order to run your container image across
  10. # the cluster.
  11. - name: outerloop-deployment
  12. kubernetes:
  13. inlined: |
  14. kind: Deployment
  15. apiVersion: apps/v1
  16. metadata:
  17. name: {{RESOURCE_NAME}}
  18. spec:
  19. replicas: 1
  20. selector:
  21. matchLabels:
  22. app: {{RESOURCE_NAME}}
  23. template:
  24. metadata:
  25. labels:
  26. app: {{RESOURCE_NAME}}
  27. spec:
  28. containers:
  29. - name: {{RESOURCE_NAME}}
  30. image: {{CONTAINER_IMAGE}}
  31. ports:
  32. - name: http
  33. containerPort: {{CONTAINER_PORT}}
  34. protocol: TCP
  35. resources:
  36. limits:
  37. memory: "1024Mi"
  38. cpu: "500m"
  39. # This will create a Service so your Deployment is accessible.
  40. # Depending on your cluster, you may modify this code so it's a
  41. # NodePort, ClusterIP or a LoadBalancer service.
  42. - name: outerloop-service
  43. kubernetes:
  44. inlined: |
  45. apiVersion: v1
  46. kind: Service
  47. metadata:
  48. name: {{RESOURCE_NAME}}
  49. spec:
  50. ports:
  51. - name: "{{CONTAINER_PORT}}"
  52. port: {{CONTAINER_PORT}}
  53. protocol: TCP
  54. targetPort: {{CONTAINER_PORT}}
  55. selector:
  56. app: {{RESOURCE_NAME}}
  57. type: NodePort
  • Devfile 中最后添加的是 Kubernetes ingress 组件,如下所示:

Details

Ingress 命令

  1. - name: outerloop-url
  2. kubernetes:
  3. inlined: |
  4. apiVersion: networking.k8s.io/v1
  5. kind: Ingress
  6. metadata:
  7. name: {{RESOURCE_NAME}}
  8. spec:
  9. rules:
  10. - host: "{{DOMAIN_NAME}}"
  11. http:
  12. paths:
  13. - path: "/"
  14. pathType: Prefix
  15. backend:
  16. service:
  17. name: {{RESOURCE_NAME}}
  18. port:
  19. number: {{CONTAINER_PORT}}
  • 下面是 devfile.yaml 示例,你可以通过示例文件了解如何同时使用命令和变量设置。请检查你的 Devfile 以匹配或更新变量,如下所示:

Details

最终 Devfile

  1. commands:
  2. - exec:
  3. commandLine: npm install
  4. component: runtime
  5. group:
  6. isDefault: true
  7. kind: build
  8. workingDir: ${PROJECT_SOURCE}
  9. id: install
  10. - exec:
  11. commandLine: npm start
  12. component: runtime
  13. group:
  14. isDefault: true
  15. kind: run
  16. workingDir: ${PROJECT_SOURCE}
  17. id: run
  18. - exec:
  19. commandLine: npm run debug
  20. component: runtime
  21. group:
  22. isDefault: true
  23. kind: debug
  24. workingDir: ${PROJECT_SOURCE}
  25. id: debug
  26. - exec:
  27. commandLine: npm test
  28. component: runtime
  29. group:
  30. isDefault: true
  31. kind: test
  32. workingDir: ${PROJECT_SOURCE}
  33. id: test
  34. # This is the main "composite" command that will run all below commands
  35. - id: deploy
  36. composite:
  37. commands:
  38. - build-image
  39. - k8s-deployment
  40. - k8s-service
  41. - k8s-url
  42. group:
  43. isDefault: true
  44. kind: deploy
  45. # Below are the commands and their respective components that they are "linked" to deploy
  46. - id: build-image
  47. apply:
  48. component: outerloop-build
  49. - id: k8s-deployment
  50. apply:
  51. component: outerloop-deployment
  52. - id: k8s-service
  53. apply:
  54. component: outerloop-service
  55. - id: k8s-url
  56. apply:
  57. component: outerloop-url
  58. components:
  59. - container:
  60. args:
  61. - tail
  62. - -f
  63. - /dev/null
  64. endpoints:
  65. - name: http-node
  66. targetPort: 3000
  67. - exposure: none
  68. name: debug
  69. targetPort: 5858
  70. env:
  71. - name: DEBUG_PORT
  72. value: "5858"
  73. image: registry.suse.com/bci/nodejs:16:latest
  74. memoryLimit: 1024Mi
  75. mountSources: true
  76. name: runtime
  77. # This will build the container image before deployment
  78. - name: outerloop-build
  79. image:
  80. dockerfile:
  81. buildContext: ${PROJECT_SOURCE}
  82. rootRequired: false
  83. uri: ./Dockerfile
  84. imageName: "{{CONTAINER_IMAGE}}"
  85. # This will create a Deployment in order to run your container image across
  86. # the cluster.
  87. - name: outerloop-deployment
  88. kubernetes:
  89. inlined: |
  90. kind: Deployment
  91. apiVersion: apps/v1
  92. metadata:
  93. name: {{RESOURCE_NAME}}
  94. spec:
  95. replicas: 1
  96. selector:
  97. matchLabels:
  98. app: {{RESOURCE_NAME}}
  99. template:
  100. metadata:
  101. labels:
  102. app: {{RESOURCE_NAME}}
  103. spec:
  104. containers:
  105. - name: {{RESOURCE_NAME}}
  106. image: {{CONTAINER_IMAGE}}
  107. ports:
  108. - name: http
  109. containerPort: {{CONTAINER_PORT}}
  110. protocol: TCP
  111. resources:
  112. limits:
  113. memory: "1024Mi"
  114. cpu: "500m"
  115. # This will create a Service so your Deployment is accessible.
  116. # Depending on your cluster, you may modify this code so it's a
  117. # NodePort, ClusterIP or a LoadBalancer service.
  118. - name: outerloop-service
  119. kubernetes:
  120. inlined: |
  121. apiVersion: v1
  122. kind: Service
  123. metadata:
  124. name: {{RESOURCE_NAME}}
  125. spec:
  126. ports:
  127. - name: "{{CONTAINER_PORT}}"
  128. port: {{CONTAINER_PORT}}
  129. protocol: TCP
  130. targetPort: {{CONTAINER_PORT}}
  131. selector:
  132. app: {{RESOURCE_NAME}}
  133. type: NodePort
  134. - name: outerloop-url
  135. kubernetes:
  136. inlined: |
  137. apiVersion: networking.k8s.io/v1
  138. kind: Ingress
  139. metadata:
  140. name: {{RESOURCE_NAME}}
  141. spec:
  142. rules:
  143. - host: "{{DOMAIN_NAME}}"
  144. http:
  145. paths:
  146. - path: "/"
  147. pathType: Prefix
  148. backend:
  149. service:
  150. name: {{RESOURCE_NAME}}
  151. port:
  152. number: {{CONTAINER_PORT}}
  153. metadata:
  154. description: Stack with Node.js 16
  155. displayName: Node.js Runtime
  156. icon: https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg
  157. language: JavaScript
  158. name: my-node-app
  159. projectType: Node.js
  160. tags:
  161. - Node.js
  162. - Express
  163. - ubi8
  164. version: 2.1.1
  165. schemaVersion: 2.2.0
  166. starterProjects:
  167. - git:
  168. remotes:
  169. origin: https://github.com/odo-devfiles/nodejs-ex.git
  170. name: nodejs-starter
  171. # Add the following variables code anywhere in devfile.yaml
  172. # This MUST be a container registry you are able to access
  173. variables:
  174. CONTAINER_IMAGE: docker.io/<INSERTUSERNAME>/node-odo-example
  175. RESOURCE_NAME: my-node-app
  176. CONTAINER_PORT: "3000"
  177. DOMAIN_NAME: node.example.com
  1. 现在,你可以运行命令 odo deploy 将应用程序部署到集群:

ODO 与 Rancher Desktop - 图3警告

你可能会遇到 unauthorized: image 错误,这是因为该镜像可能未包含在 Rancher Desktop 允许的镜像列表中。要解决该错误,请在 Preferences > Container Engine > Allowed Images 中添加镜像,然后点击 Apply 立即更新允许的镜像列表。

Details

示例输出

  1. $ odo deploy
  2. __
  3. / \__ Running the application in Deploy mode using my-node-app Devfile
  4. \__/ \ Namespace: odo-dev
  5. / \__/ odo version: v3.13.0
  6. \__/
  7. Building & Pushing Image: docker.io/arjsin/nodejs-odo-example
  8. Building image locally ...
  9. [+] Building 2.7s (9/9) FINISHED
  10. => [internal] load build definition from Dockerfile 0.0s
  11. => => transferring dockerfile: 405B 0.0s
  12. => [internal] load .dockerignore 0.0s
  13. => => transferring context: 364B 0.0s
  14. => [internal] load metadata for registry.suse.com/bci/nodejs:16 2.2s
  15. => [1/4] FROM registry.suse.com/bci/nodejs:16@sha256:dda0e616a0fcb3dc589 0.0s
  16. => [internal] load build context 0.0s
  17. => => transferring context: 5.14kB 0.0s
  18. => CACHED [2/4] COPY package*.json ./ 0.0s
  19. => CACHED [3/4] RUN npm install --production 0.0s
  20. => [4/4] COPY . /opt/app-root/src 0.0s
  21. => exporting to image 0.4s
  22. => => exporting layers 0.4s
  23. => => writing image sha256:c6d3ed7d9fb4736d3c4e95b54054533f79d64d3a01e65 0.0s
  24. => => naming to docker.io/arjsin/nodejs-odo-example 0.0s
  25. Building image locally [3s]
  26. Pushing image to container registry ...
  27. Using default tag: latest
  28. The push refers to repository [docker.io/arjsin/nodejs-odo-example]
  29. 20658d9b13ba: Pushed
  30. 7b1ee26c3aea: Pushed
  31. 067890bef08d: Pushed
  32. d08e96dfc7bc: Pushed
  33. 174c0e293bd0: Pushed
  34. latest: digest: sha256:ca598fc0c5278e8d00cba41e14914f1d3f7a3561bd4a324f2ffcd33b166135ad size: 1368
  35. Pushing image to container registry [30s]
  36. Deploying Kubernetes Component: my-node-app
  37. Creating resource Deployment/my-node-app
  38. Deploying Kubernetes Component: my-node-app
  39. Creating resource Service/my-node-app
  40. Deploying Kubernetes Component: my-node-app
  41. Creating resource Ingress/my-node-app
  42. Your Devfile has been successfully deployed

步骤:odo describe component

现在,你可以使用命令 odo describe component 查看 Devfile 中的信息,例如 Kubernetes 组件、ingress 和访问应用程序的 URL:

  1. odo describe component

Details

示例输出

  1. $ odo describe component
  2. Name: my-nodejs-app
  3. Display Name: Node.js Runtime
  4. Project Type: Node.js
  5. Language: JavaScript
  6. Version: 2.2.0
  7. Description: Node.js 18 application
  8. Tags: Node.js, Express, ubi8
  9. Running in: None
  10. Supported odo features:
  11. Dev: true
  12. Deploy: false
  13. Debug: true
  14. Commands:
  15. install
  16. Type: exec
  17. Group: build
  18. Command Line: "npm install"
  19. Component: runtime
  20. Component Type: container
  21. run
  22. Type: exec
  23. Group: run
  24. Command Line: "npm start"
  25. Component: runtime
  26. Component Type: container
  27. debug
  28. Type: exec
  29. Group: debug
  30. Command Line: "npm run debug"
  31. Component: runtime
  32. Component Type: container
  33. test
  34. Type: exec
  35. Group: test
  36. Command Line: "npm test"
  37. Component: runtime
  38. Component Type: container
  39. Container components:
  40. runtime
  41. Source Mapping: /projects

步骤:odo delete component

测试完成后,你可以使用命令 odo delete component 释放 odo 使用的资源:

  1. odo delete component

Details

示例输出

  1. $ odo delete component
  2. Searching resources to delete, please wait...
  3. This will delete "my-node-app" from the namespace "odo-dev".
  4. The following resources will get deleted from cluster:
  5. - Deployment: my-node-app
  6. - Service: my-node-app
  7. - Ingress: my-node-app
  8. ?Are you sure you want to delete "my-node-app" and all its resources?Yes
  9. Deleting resources from cluster [52ms]
  10. The component "my-node-app" is successfully deleted from namespace "odo-dev"