ローカルでAIコードエディタ「Cursor」を使ってみよう
はじめに
なぜこの記事を作成したのか
ソースコード全体を見て依存関係を考慮して提案をしてくれるAIコードエディタは無いかと探していてCursorにたどり着いたため備忘録的な意味も含めて書きました。
この記事のスコープ
- Cursor
- 概要
- インストール方法
- 使い方
- デモ(OKEクラスタの構築)
- プライバシーポリシーについて
※ 本記事はWindows環境での内容となります。
実行環境のWindows version
Windowsマーク + R で「ファイル名を指定して実行」を開き、winver
と入力してOKをクリックする
Cursor概要
Cursorとは?
Cursorは、AIアシスタント機能を統合したモダンなコードエディタです。
従来のように開発中にブラウザでAIに質問する手間を省き、エディタ上で直接AIとやり取りしながらコーディングができます。
主な特徴は:
- コードエディタ内でAIとチャット
- コードベース全体を理解した提案
- VSCode拡張機能との互換性
- マルチプラットフォーム対応(Windows/Mac/Linux)
価格設定
CursorにはHobby、Pro、Businessプランがあります。
プラン | 価格 | 特徴 |
---|---|---|
Hobby | 無料 | 基本機能+Proプラン2週間トライアル |
Pro | $20/月 | 高度な機能、一部制限解除 |
Business | $40/ユーザー/月 | エンタープライズ向け機能 |
Hobbyプランは無料 + Proプランの2週間トライアルがあるためお試しで使うには十分かと思います。
その他各プラン毎の制限など詳しくは Pricingを参照してください。
インストール方法
インストール手順
- 公式ダウンロードページから対象OSのインストーラーを取得
- ダウンロードしたインストーラーを実行
初期設定
インストール完了後、以下の初期設定画面が表示されます:
下記設定項目を設定していきます。
設定が完了したら右下の Continue ボタンを押下します。
Keyboard
Vim, Emacs, Atom, Sublime, and Jetbrains Keybindings.
エディタのキーボードバインディング設定を選べます。
- VSCode
- Vim
- Jetbrains
- Emacs
- Sublime
- Atom
現時点では上記から好みの設定を選びます。
デフォルトではVSCodeが選択されます。
Language for AI
You can specify a non-English language for the AI.
チャットで使用する言語を設定します。
日本語を設定する際は 日本語 と設定します。
Codebase-wide
Compute embeddings for codebase-wide questions.
ディレクトリ(コードベース)全体に対してAIへ質問するための機能でソースコード全体がEmbedding(埋め込み)されます。
これを有効にすることでディレクトリ全体を読み込ませたうえで質問をする機能が使えるようになります。
Add to Command Line
Launch from the command line using 'code' or 'cursor'
ターミナルからCursorを起動するコマンドをインストールするかどうかの項目です。
インストールするとcode もしくは cursor コマンドで開けるようになります。
VSCodeを使用している方は code で開いたりすると思いますので私は cursor をインストールしました。
プライバシーモードの設定
これを有効にすることにより、Chat機能で送信したコードなどを外部に保存しないようにします。
FAQ に下記記載があります。
With Privacy Mode enabled, none of your code will ever be stored by us or any third-party.
Otherwise, we may collect prompts, code snippets and telemetry data to improve Cursor.
You can read more about Privacy Mode here.
### 日本語訳
プライバシーモードを有効にすると、あなたのコードが当社またはサードパーティによって保存されることはありません。
そうでない場合は、Cursorを改善するためにプロンプト、コードスニペット、遠隔測定データを収集することがあります。
プライバシーモードについての詳細はこちらをご覧ください。
設定方法
Cursorの右上歯車アイコンを押下します。
開いた Cursor Settings
ページを少し下に行くと 「Privacy mode」があります。
プルダウンを開いて enabled
に設定します。
使い方
フォルダを開く
Cursorを開くと下記画面が表示されます。
Open a folder
を押下して開きたいディレクトリを指定します。
私はwindowsからwsl2/ubuntuのディレクトリを開きたいので \\wsl$\Ubuntu\home\myuser\test_cursor_ai_editor
のように指定して開きました。
AIに質問をしてみる
試しにAIに質問をしてみます。
Ctrl + L
でChatを開きます。
下記の質問をChatで行ってみました。
Terraformを使用して http://localhost:8080 にアクセスすると
Nginxのトップページを表示するコードを提案してください。
すると以下のようなコードを提案してくれました。
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0.0"
}
}
}
provider "docker" {}
resource "docker_image" "nginx" {
name = "nginx:latest"
keep_locally = false
}
resource "docker_container" "nginx" {
image = docker_image.nginx.image_id
name = "nginx-server"
ports {
internal = 80
external = 8080
}
}
Chat回答全文はこちら
Terraformを使用してNginxをデプロイするための基本的なコードを提案させていただきます。
まず、必要なファイルを作成しましょう:
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0.0"
}
}
}
provider "docker" {}
resource "docker_image" "nginx" {
name = "nginx:latest"
keep_locally = false
}
resource "docker_container" "nginx" {
image = docker_image.nginx.image_id
name = "nginx-server"
ports {
internal = 80
external = 8080
}
}
このコードで以下のことを実現します:
- Dockerプロバイダーの設定
- Nginxの公式イメージのプル
- コンテナの作成と8080ポートの公開
使用方法: - 以下のコマンドを実行してください:
terraform init
terraform apply
-
デプロイが完了したら、ブラウザで
http://localhost:8080
にアクセスすると、Nginxのデフォルトページが表示されます。 -
リソースを削除する場合は:
terraform destroy
注意点:
- Dockerがローカルマシンにインストールされている必要があります
- Dockerデーモンが実行されている必要があります
- 8080ポートが他のアプリケーションで使用されていないことを確認してください
提案されたコードを早速記述したいのですが、Cursorの便利なところの一つとして提案されたコードをそのままApplyできます。
その際に対象ファイルが無かった場合は新規作成もしてくれるというありがたい機能があります。
Chat右上の ▷ Apply
を押してみましょう
すると、diffが表示されます。
ここでAccept Ctrl+Shift+Y
か Reject Ctrl+N
を選択して押下(もしくはショートカットキーを実行)することで提案されたコードを記述を受け入れるか拒否するか決めることができます。
Accept Ctrl+Shift+Y
ボタンを押下してファイルを作成したのちにterraform applyしてみましょう。
ここでも便利な機能として、提案されたコマンドをそのまま実行することができます。
▷ Run
ボタンを押下するとターミナルが起動し、実行してくれます。
無事 terraform init, applyコマンドを実行してくれました。
出力
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding kreuzwerker/docker versions matching "~> 3.0.0"...
- Installing kreuzwerker/docker v3.0.2...
- Installed kreuzwerker/docker v3.0.2 (self-signed, key ID BD080C4571C6104C)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html
Terraform has created a lock file .terraform.lock.hcl
to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running
"terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
$ terraform apply
Terraform used the selected providers to generate the
following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# docker_container.nginx will be created
+ resource "docker_container" "nginx" {
+ attach =
false
+ bridge =
(known after apply)
+ command =
(known after apply)
+ container_logs =
(known after apply)
+ container_read_refresh_timeout_milliseconds =
15000
+ entrypoint =
(known after apply)
+ env =
(known after apply)
+ exit_code =
(known after apply)
+ hostname =
(known after apply)
+ id =
(known after apply)
+ image =
(known after apply)
+ init =
(known after apply)
+ ipc_mode =
(known after apply)
+ log_driver =
(known after apply)
+ logs =
false
+ must_run =
true
+ name =
"nginx-server"
+ network_data =
(known after apply)
+ read_only =
false
+ remove_volumes =
true
+ restart =
"no"
+ rm =
false
+ runtime =
(known after apply)
+ security_opts =
(known after apply)
+ shm_size =
(known after apply)
+ start =
true
+ stdin_open =
false
+ stop_signal =
(known after apply)
+ stop_timeout =
(known after apply)
+ tty =
false
+ wait =
false
+ wait_timeout =
60
+ healthcheck {
+ interval = (known after apply)
+ retries = (known after apply)
+ start_period = (known after apply)
+ test = (known after apply)
+ timeout = (known after apply)
}
+ labels {
+ label = (known after apply)
+ value = (known after apply)
}
+ ports {
+ external = 8080
+ internal = 80
+ ip = "0.0.0.0"
+ protocol = "tcp"
}
}
# docker_image.nginx will be created
+ resource "docker_image" "nginx" {
+ id = (known after apply)
+ image_id = (known after apply)
+ keep_locally = false
+ name = "nginx:latest"
+ repo_digest = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
terraform applyは --auto-approveオプションをつけなければ手動でyを入力するまでapply開始されないのでyes を押します。
yes入力後の出力
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
docker_image.nginx: Creating...
docker_image.nginx: Creation complete after 8s [id=sha256:f876bfc1cc63d905bb9c8ebc5adc98375bb8e22920959719d1a96e8f594868fanginx:latest]
docker_container.nginx: Creating...
docker_container.nginx: Creation complete after 1s [id=ef1b5a28e9aaede556a3000d3d4b622e782e892e20090a57c10c7c2726f25e29]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
applyが成功したら実際にチェックしてみましょう
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ef1b5a28e9aa f876bfc1cc63 "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp nginx-server
http://localhost:8080 へアクセスしてみます。
無事Nginxのトップページが表示されました。
ここまでは普通のAIチャットなどでもそこまで変わらないかと思います。
次は複数ファイルを読み込んだうえでの動作を見てみましょう
デモ(OKEクラスタの構築)
どうせなら1からAIに作ってもらいつつ検証してみましょう。
少し長くなりますが、codebaseを使用して一切自分ではコードを記述せずOracle Cloudで提供しているOKEリソースを作成してみます。
事前に以下ディレクトリ構成を作っておきます。
中身は一切記述していない状態です。
$ tree test_cursor_all_dir/
test_cursor_all_dir/
├── kubernetes
│ └── deployments.yaml
└── terraform
├── env
│ └── dev
│ ├── main.tf
│ ├── provider.tf
│ ├── terraform.tfvars
│ └── variables.tf
└── modules
├── oke
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
└── vcn
├── main.tf
├── outputs.tf
└── variables.tf
そして雑な質問を投げかけます。
terraformでoci vcn, okeを作成したいです。
ローカルのブラウザからアクセスするとNginxのトップページが起動されるようにしてください。
検証のためコストを最小限にしてください。
下記ディレクトリ構成を参考に提案してください。
$ tree test_cursor_all_dir/
test_cursor_all_dir/
├── kubernetes
│ └── deployments.yaml
└── terraform
├── env
│ └── dev
│ ├── main.tf
│ ├── provider.tf
│ ├── terraform.tfvars
│ └── variables.tf
└── modules
├── oke
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
└── vcn
├── main.tf
├── outputs.tf
└── variables.tf
上記をChatに記載し、Ctrl + Enter
もしくは codebase
ボタンを押下してディレクトリ全体を読み込ませて質問してみましょう。
すると Search completed(11 files)
と表示されました。
実際に11個のファイルが読み込まれたようです。
事前に作成したファイル(空ですが)を全て読み込んだようです。
回答全文
OCIでVCNとOKEを構築し、Nginxを動かす構成を提案させていただきます。コスト最小限のため、Always Freeの範囲内で構築します。
まず、各ファイルの内容を示します:
variable "compartment_id" {
description = "Compartment ID"
type = string
}
variable "vcn_display_name" {
description = "VCN Display Name"
type = string
default = "test-vcn"
}
variable "vcn_dns_label" {
description = "VCN DNS Label"
type = string
default = "testvcn"
}
resource "oci_core_vcn" "vcn" {
compartment_id = var.compartment_id
cidr_blocks = ["10.0.0.0/16"]
display_name = var.vcn_display_name
dns_label = var.vcn_dns_label
}
resource "oci_core_internet_gateway" "ig" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
display_name = "internet-gateway"
}
resource "oci_core_route_table" "public_rt" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
display_name = "public-route-table"
route_rules {
destination = "0.0.0.0/0"
network_entity_id = oci_core_internet_gateway.ig.id
}
}
resource "oci_core_subnet" "public_subnet" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
cidr_block = "10.0.1.0/24"
display_name = "public-subnet"
route_table_id = oci_core_route_table.public_rt.id
security_list_ids = [oci_core_security_list.public_sl.id]
}
resource "oci_core_security_list" "public_sl" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
display_name = "public-security-list"
ingress_security_rules {
protocol = "6"
source = "0.0.0.0/0"
tcp_options {
min = 80
max = 80
}
}
}
output "vcn_id" {
value = oci_core_vcn.vcn.id
}
output "subnet_id" {
value = oci_core_subnet.public_subnet.id
}
variable "compartment_id" {
description = "Compartment ID"
type = string
}
variable "cluster_name" {
description = "OKE Cluster Name"
type = string
default = "test-cluster"
}
variable "vcn_id" {
description = "VCN ID"
type = string
}
variable "subnet_id" {
description = "Subnet ID"
type = string
}
resource "oci_containerengine_cluster" "oke_cluster" {
compartment_id = var.compartment_id
kubernetes_version = "v1.26.2"
name = var.cluster_name
vcn_id = var.vcn_id
type = "BASIC_CLUSTER"
endpoint_config {
is_public_ip_enabled = true
subnet_id = var.subnet_id
}
options {
service_lb_subnet_ids = [var.subnet_id]
}
}
resource "oci_containerengine_node_pool" "oke_node_pool" {
cluster_id = oci_containerengine_cluster.oke_cluster.id
compartment_id = var.compartment_id
kubernetes_version = "v1.26.2"
name = "test-node-pool"
node_shape = "VM.Standard.A1.Flex"
node_shape_config {
memory_in_gbs = 6
ocpus = 1
}
node_config_details {
placement_configs {
availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
subnet_id = var.subnet_id
}
size = 1
}
node_source_details {
image_id = data.oci_core_images.node_pool_images.images[0].id
source_type = "IMAGE"
}
}
data "oci_identity_availability_domains" "ads" {
compartment_id = var.compartment_id
}
data "oci_core_images" "node_pool_images" {
compartment_id = var.compartment_id
operating_system = "Oracle Linux"
operating_system_version = "8"
shape = "VM.Standard.A1.Flex"
}
variable "tenancy_ocid" {}
variable "user_ocid" {}
variable "fingerprint" {}
variable "private_key_path" {}
variable "region" {}
variable "compartment_id" {}
provider "oci" {
tenancy_ocid = var.tenancy_ocid
user_ocid = var.user_ocid
fingerprint = var.fingerprint
private_key_path = var.private_key_path
region = var.region
}
module "vcn" {
source = "../../modules/vcn"
compartment_id = var.compartment_id
}
module "oke" {
source = "../../modules/oke"
compartment_id = var.compartment_id
vcn_id = module.vcn.vcn_id
subnet_id = module.vcn.subnet_id
}
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
selector:
app: nginx
この構成の特徴:
- コスト最小化のため:
- Always Free対象のVM.Standard.A1.Flex(ARM)を使用
- ノードプール数を1に設定
- メモリを6GB、OCPUを1に設定
- セキュリティ:
- パブリックサブネットのセキュリティリストで80番ポートのみ許可
- OKEクラスターはパブリックエンドポイントを使用
- Nginx構成:
- シンプルなデプロイメント(レプリカ数1)
- ロードバランサータイプのサービスを使用
デプロイ手順:
- terraform initを実行
- terraform planを実行して構成を確認
- terraform applyを実行してインフラを作成
- OKEクラスターのkubeconfigを取得
- kubectl apply -f kubernetes/deployments.yamlを実行
- kubectl get svcでNginxサービスの外部IPを確認し、ブラウザからアクセス
これで、ブラウザから外部IPにアクセスすると、Nginxのデフォルトページが表示されます。
コードの内容はひとまず置いておいて、一度applyしてみましょう。
terraform.tfvarsにOCIのユーザー認証情報を記述します。
記述が終わったらapplyしていきます。
cd terraform/env/dev
terraform init
terraform plan
terraform apply
すると下記エラーが発生しました。
Kubernetesのバージョンがサポートされていないバージョンのようです。
╷
│ Error: 400-InvalidParameter, Invalid kubernetesVersion: Invalid Kubernetes version v1.26.2. Supported versions: [v1.28.2, v1.28.10, v1.29.1, v1.30.1, v1.31.1]
│ Suggestion: Please update the parameter(s) in the Terraform config as per error message Invalid kubernetesVersion: Invalid Kubernetes version v1.26.2. Supported versions: [v1.28.2, v1.28.10, v1.29.1, v1.30.1, v1.31.1]
│ Documentation: https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/containerengine_cluster
│ API Reference: https://docs.oracle.com/iaas/api/#/en/containerengine/20180222/Cluster/CreateCluster
│ Request Target: POST https://containerengine.ap-tokyo-1.oci.oraclecloud.com/20180222/clusters
│ Provider version: 6.21.0, released on 2024-12-22. This provider is 3 Update(s) behind to current.
│ Service: Containerengine Cluster
│ Operation Name: CreateCluster
│ OPC request ID: c6dfa135c5377db810d39d0038fe650b/FFA6BB297E9DE1587EF4F0C20A9A1596/A106A20FFCE7E2BBBD4E5372323DF747
│
│
│ with module.oke.oci_containerengine_cluster.oke_cluster,
│ on ../../modules/oke/main.tf line 1, in resource "oci_containerengine_cluster" "oke_cluster":
│ 1: resource "oci_containerengine_cluster" "oke_cluster" {
│
早速AIにChatで聞いてみましょう
以下をChatに記述し Ctrl + Enter
をしてディレクトリ全体を読み込ませて質問してみます。
$ terraform apply
╷
│ Error: 400-InvalidParameter, Invalid kubernetesVersion: Invalid Kubernetes version v1.26.2. Supported versions: [v1.28.2, v1.28.10, v1.29.1, v1.30.1, v1.31.1]
│ Suggestion: Please update the parameter(s) in the Terraform config as per error message Invalid kubernetesVersion: Invalid Kubernetes version v1.26.2. Supported versions: [v1.28.2, v1.28.10, v1.29.1, v1.30.1, v1.31.1]
│ Documentation: https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/containerengine_cluster
│ API Reference: https://docs.oracle.com/iaas/api/#/en/containerengine/20180222/Cluster/CreateCluster
│ Request Target: POST https://containerengine.ap-tokyo-1.oci.oraclecloud.com/20180222/clusters
│ Provider version: 6.21.0, released on 2024-12-22. This provider is 3 Update(s) behind to current.
│ Service: Containerengine Cluster
│ Operation Name: CreateCluster
│ OPC request ID: c6dfa135c5377db810d39d0038fe650b/FFA6BB297E9DE1587EF4F0C20A9A1596/A106A20FFCE7E2BBBD4E5372323DF747
│
│
│ with module.oke.oci_containerengine_cluster.oke_cluster,
│ on ../../modules/oke/main.tf line 1, in resource "oci_containerengine_cluster" "oke_cluster":
│ 1: resource "oci_containerengine_cluster" "oke_cluster" {
│
上記エラーが発生しました。
修正コードを提案してください。
回答はバージョンをv1.28.2にしましょうという回答を貰いました。(なぜ最新バージョンを提案しないかはさておき)
回答全文
このエラーは、指定されたKubernetesバージョン(v1.26.2)が現在サポートされていないことを示しています。
以下のようにmain.tf
を修正することを提案します:
resource "oci_containerengine_cluster" "oke_cluster" {
compartment_id = var.compartment_id
kubernetes_version = "v1.28.2" # サポートされているバージョンに更新
name = var.cluster_name
vcn_id = var.vcn_id
type = "BASIC_CLUSTER"
endpoint_config {
is_public_ip_enabled = true
subnet_id = var.subnet_id
}
options {
service_lb_subnet_ids = [var.subnet_id]
}
}
resource "oci_containerengine_node_pool" "oke_node_pool" {
cluster_id = oci_containerengine_cluster.oke_cluster.id
compartment_id = var.compartment_id
kubernetes_version = "v1.28.2" # クラスターと同じバージョンに更新
name = "test-node-pool"
node_shape = "VM.Standard.A1.Flex"
node_shape_config {
memory_in_gbs = 6
ocpus = 1
}
node_config_details {
placement_configs {
availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
subnet_id = var.subnet_id
}
size = 1
}
node_source_details {
image_id = data.oci_core_images.node_pool_images.images[0].id
source_type = "IMAGE"
}
}
回答の通り修正を行い、再度applyしてみます。
OKEクラスタ作成に少々時間がかかるので気長に待ちます。
ここからいくつか質問とapplyを繰り返しました。
最終的な構成とコードについては下記となりました。
コード
$ tree
.
├── kubernetes
│ └── deployments.yaml
└── terraform
├── env
│ └── dev
│ ├── main.tf
│ ├── provider.tf
│ ├── terraform.tfstate # terraform apply時に自動生成される
│ ├── terraform.tfstate.backup # terraform apply時に自動生成される
│ ├── terraform.tfvars
│ └── variables.tf
└── modules
├── oke
│ ├── main.tf
│ └── variables.tf
└── vcn
├── main.tf
├── outputs.tf
└── variables.tf
module "vcn" {
source = "../../modules/vcn"
compartment_id = var.compartment_id
}
module "oke" {
source = "../../modules/oke"
compartment_id = var.compartment_id
vcn_id = module.vcn.vcn_id
node_pool_subnet_id = module.vcn.node_pool_subnet_id
service_lb_subnet_id = module.vcn.service_lb_subnet_id
k8s_api_subnet_id = module.vcn.k8s_api_subnet_id
}
provider "oci" {
tenancy_ocid = var.tenancy_ocid
user_ocid = var.user_ocid
fingerprint = var.fingerprint
private_key_path = var.private_key_path
region = var.region
}
tenancy_ocid="xxxxx"
user_ocid="xxxxx"
fingerprint="xxxxx"
private_key_path="xxxxx"
region="xxxxx"
compartment_id="xxxxx"
variable "tenancy_ocid" {}
variable "user_ocid" {}
variable "fingerprint" {}
variable "private_key_path" {}
variable "region" {}
variable "compartment_id" {}
resource "oci_containerengine_cluster" "oke_cluster" {
compartment_id = var.compartment_id
kubernetes_version = "v1.28.2"
name = var.cluster_name
vcn_id = var.vcn_id
type = "BASIC_CLUSTER"
cluster_pod_network_options {
cni_type = "OCI_VCN_IP_NATIVE"
}
endpoint_config {
is_public_ip_enabled = true
subnet_id = var.k8s_api_subnet_id
}
options {
service_lb_subnet_ids = [var.service_lb_subnet_id]
}
}
resource "oci_containerengine_node_pool" "oke_node_pool" {
cluster_id = oci_containerengine_cluster.oke_cluster.id
compartment_id = var.compartment_id
kubernetes_version = "v1.28.2"
name = "test-node-pool"
node_shape = "VM.Standard.A1.Flex"
node_shape_config {
memory_in_gbs = 6
ocpus = 1
}
node_config_details {
placement_configs {
availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
subnet_id = var.node_pool_subnet_id
}
size = 1
node_pool_pod_network_option_details {
cni_type = "OCI_VCN_IP_NATIVE"
pod_subnet_ids = [var.node_pool_subnet_id]
}
}
node_source_details {
image_id = data.oci_core_images.node_pool_images.images[0].id
source_type = "IMAGE"
}
}
data "oci_identity_availability_domains" "ads" {
compartment_id = var.compartment_id
}
data "oci_core_images" "node_pool_images" {
compartment_id = var.compartment_id
operating_system = "Oracle Linux"
operating_system_version = "8"
shape = "VM.Standard.A1.Flex"
}
variable "compartment_id" {
description = "Compartment ID"
type = string
}
variable "cluster_name" {
description = "OKE Cluster Name"
type = string
default = "test-cluster"
}
variable "vcn_id" {
description = "VCN ID"
type = string
}
variable "node_pool_subnet_id" {
description = "Node Pool Subnet ID"
type = string
}
variable "service_lb_subnet_id" {
description = "Service Load Balancer Subnet ID"
type = string
}
variable "k8s_api_subnet_id" {
description = "Kubernetes API Endpoint Subnet ID"
type = string
}
resource "oci_core_vcn" "vcn" {
compartment_id = var.compartment_id
cidr_blocks = [var.vcn_cidr]
display_name = "vcn-oke"
}
resource "oci_core_internet_gateway" "igw" {
compartment_id = var.compartment_id
display_name = "igw-oke"
enabled = true
vcn_id = oci_core_vcn.vcn.id
}
resource "oci_core_nat_gateway" "nat_gateway" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
display_name = "nat-gateway-oke"
}
resource "oci_core_default_route_table" "public_rt" {
manage_default_resource_id = oci_core_vcn.vcn.default_route_table_id
display_name = "public-route-table"
route_rules {
description = "traffic to/from internet"
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
network_entity_id = oci_core_internet_gateway.igw.id
}
}
resource "oci_core_route_table" "private_rt" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
display_name = "private-route-table-oke"
route_rules {
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
network_entity_id = oci_core_nat_gateway.nat_gateway.id
}
}
resource "oci_core_subnet" "node_pool_subnet" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
cidr_block = var.node_subnet
display_name = "node-subnet-oke"
prohibit_public_ip_on_vnic = true
route_table_id = oci_core_route_table.private_rt.id
security_list_ids = [oci_core_security_list.node_sec_list.id]
}
resource "oci_core_subnet" "service_lb_subnet" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
cidr_block = var.lb_subnet
display_name = "svc-lb-subnet-oke"
prohibit_public_ip_on_vnic = false
route_table_id = oci_core_default_route_table.public_rt.id
security_list_ids = [oci_core_security_list.service_lb_sl.id]
}
resource "oci_core_subnet" "k8s_api_subnet" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
cidr_block = var.k8s_api_subnet
display_name = "k8s-api-subnet-oke"
prohibit_public_ip_on_vnic = false
route_table_id = oci_core_default_route_table.public_rt.id
security_list_ids = [oci_core_security_list.kubernetes_api_endpoint_sl.id]
}
resource "oci_core_security_list" "node_sec_list" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
display_name = "node-sec-list"
egress_security_rules {
description = "Allow pods on one worker node to communicate with pods on other worker nodes"
destination = var.node_subnet
destination_type = "CIDR_BLOCK"
protocol = "all"
stateless = false
}
egress_security_rules {
description = "Access to Kubernetes API Endpoint"
destination = var.k8s_api_subnet
destination_type = "CIDR_BLOCK"
protocol = "6"
stateless = false
}
egress_security_rules {
description = "Worker Nodes access to Internet"
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
protocol = "all"
stateless = false
}
ingress_security_rules {
description = "Allow pods on one worker node to communicate with pods on other worker nodes"
protocol = "all"
source = var.node_subnet
stateless = false
}
ingress_security_rules {
description = "TCP access from Kubernetes Control Plane"
protocol = "6"
source = var.k8s_api_subnet
stateless = false
}
}
resource "oci_core_security_list" "service_lb_sl" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
display_name = "svc-lb-sec-list"
}
resource "oci_core_security_list" "kubernetes_api_endpoint_sl" {
compartment_id = var.compartment_id
vcn_id = oci_core_vcn.vcn.id
display_name = "k8s-api-sec-list"
egress_security_rules {
description = "Allow Kubernetes Control Plane to communicate with OKE"
destination = "all-nrt-services-in-oracle-services-network"
destination_type = "SERVICE_CIDR_BLOCK"
protocol = "6"
stateless = false
}
egress_security_rules {
description = "All traffic to worker nodes"
destination = var.node_subnet
destination_type = "CIDR_BLOCK"
protocol = "6"
stateless = false
}
ingress_security_rules {
description = "External access to Kubernetes API endpoint"
protocol = "6"
source = "0.0.0.0/0"
stateless = false
}
ingress_security_rules {
description = "Kubernetes worker to Kubernetes API endpoint communication"
protocol = "6"
source = var.node_subnet
stateless = false
}
}
output "vcn_id" {
value = oci_core_vcn.vcn.id
}
output "node_pool_subnet_id" {
value = oci_core_subnet.node_pool_subnet.id
}
output "service_lb_subnet_id" {
value = oci_core_subnet.service_lb_subnet.id
}
output "k8s_api_subnet_id" {
value = oci_core_subnet.k8s_api_subnet.id
}
variable "compartment_id" {
description = "Compartment ID"
type = string
}
variable "vcn_display_name" {
description = "VCN Display Name"
type = string
default = "test-vcn"
}
variable "kubernetes_version" {
description = "Kubernetes version"
type = string
default = "v1.28.2"
}
variable "node_pool_name" {
description = "Node Pool name"
type = string
default = "pool1"
}
variable "node_pool_count" {
description = "Number of nodes in the node pool"
type = number
default = 1
}
variable "vcn_cidr" {
description = "VCN CIDR block"
type = string
default = "10.0.0.0/16"
}
variable "node_subnet" {
description = "Node Pool Subnet CIDR block"
type = string
default = "10.0.10.0/24"
}
variable "lb_subnet" {
description = "Load Balancer Subnet CIDR block"
type = string
default = "10.0.20.0/24"
}
variable "k8s_api_subnet" {
description = "Kubernetes API Subnet CIDR block"
type = string
default = "10.0.0.0/28"
}
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
selector:
app: nginx
そしてクラスタへデプロイしてみます。
oci ce cluster create-kubeconfig --cluster-id <cluster ocid> --file $HOME/.kube/config --region ap-tokyo-1 --token-version 2.0.0 --kube-endpoint PUBLIC_ENDPOINT
export KUBECONFIG=$HOME/.kube/config
cd kubernetes/
$ kubectl apply -f deployments.yaml
$ kubectl get service,deployment,pod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP,12250/TCP 28m
service/nginx-service LoadBalancer 10.96.10.14 132.226.6.68 80:32484/TCP 96s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 1/1 1 1 96s
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-7c79c4bf97-8ll65 1/1 Running 0 96s
無事起動していることを確認しました。
次にNginxのページが表示されるか確認します。
service/nginx-service
のEXTERNAL-IP
にアクセスしてみます。
http://132.226.6.68
無事接続できました🎵
長くなってしまいましたが、コードを記述することなくOKEを立ち上げることができました。
プライバシーポリシーについて
AI機能を使う際によく懸念されるクエリに含まれる情報の取り扱いについて調べてみましょう
プライバシーモード
前述しましたが FAQ に記載の通り
プライバシーモードを有効にすると、あなたのコードが当社またはサードパーティによって保存されることはありません。
そうでない場合は、Cursorを改善するためにプロンプト、コードスニペット、遠隔測定データを収集することがあります。
プライバシーモードについての詳細はこちらをご覧ください。
とあります。
しかし、保存されることは無いとありますが全てのリクエストはCursorのバックエンドを経由します。
このデータのライフサイクルはリクエストの存続期間終了後に破棄されます。
さらに詳細な情報が Security ページに記載があります。
ここではプライバシーモードを enabled/disabled した際の違いが記載されています。
enabledの場合の気になる部分をいくつかピックアップしてみました。
Our infrastructure is primarily hosted on AWS.
Most of our servers are in the US, with some latency-critical servers located in AWS regions in Asia (Tokyo) and Europe (London).
当社のインフラは主にAWSでホストされています。
ほとんどのサーバーは米国にあり、一部のレイテンシーが重要なサーバーはアジア(東京)とヨーロッパ(ロンドン)のAWSリージョンにあります。
一時的にでもデータが日本を離れる可能性があるようです。
業務で使用する場合は注意が必要ですね。
Note that the requests always hit our infrastructure on AWS even if you have configured your own API key for OpenAI in the settings.
設定で OpenAI 用の独自の API キーを構成している場合でも、
リクエストは常に AWS 上のインフラストラクチャに送信されることに注意してください。
自前の物を使用しても必ずCursolのバックエンドを経由する用です。
Our codebase indexing feature works as follows: when enabled, it scans the folder that you open in Cursor and computes a Merkle tree of hashes of all files.
Files and subdirectories specified by ‘.gitignore’ or ‘.cursorignore’ are ignored.
コードベースのインデックス作成機能は次のように動作します。
有効にすると、Cursor で開いたフォルダーをスキャンし、すべてのファイルのハッシュの Merkle ツリーを計算します。
‘.gitignore’またはで指定されたファイルとサブディレクトリ‘.cursorignore’は無視されます。
.gitignore, .cursorignoreファイルで読み込ませたくないファイルは指定できるようです。
また、開発中のようですが .cursorban を使用してあらゆるリクエストでファイルが送信されないようにする機能を検討しているようです。
Embedding
codebase機能またはChat機能を使用してファイルをEmbeddingした場合、メタデータはデータベースに保存されますがコードは保存されないとのことでした。
そのため、ファイル名に機密情報等を含んでいた場合は注意する必要がありそうです。
まとめ
Cursorのインストールから簡単な使い方までを記述してみました。
この記事では記載していない様々な便利機能がまだまだあります、無料のProトライアル期間を使用して使用感を試してもらえればと思います。
まだ個人開発でしか使用しておりませんが、業務でも使用できるのでは??と思いプライバシーポリシー周りも調査してみたのですが、会社規則等と照らし合わせて要検討といったところでしょうか?
ですが、サンプルとなるコードを生成させるなどするだけでもかなり作業速度は上がるかと思うのでそれだけでも使う価値はあるかと思います。
長くなってしまいましたが読んでいただきありがとうございました。
Discussion