Showing preview only (1,052K chars total). Download the full file or copy to clipboard to get everything.
Repository: nekomeowww/ollama-operator
Branch: main
Commit: ece318891898
Files: 124
Total size: 996.0 KB
Directory structure:
gitextract_tcznvur4/
├── .dockerignore
├── .github/
│ ├── FUNDING.yml
│ ├── renovate.json
│ └── workflows/
│ ├── ci.yaml
│ ├── pr-docs-build.yaml
│ ├── pr-docs-deployment.yaml
│ ├── production-docs-deployment.yaml
│ ├── release-build.yml
│ └── unstable-build.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yml
├── .krew.yaml
├── .tool-versions
├── .vscode/
│ └── settings.json
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── PROJECT
├── README.md
├── api/
│ └── ollama/
│ └── v1/
│ ├── groupversion_info.go
│ ├── model_types.go
│ └── zz_generated.deepcopy.go
├── cmd/
│ ├── kollama/
│ │ └── main.go
│ └── ollama-operator/
│ └── main.go
├── config/
│ ├── crd/
│ │ ├── bases/
│ │ │ └── ollama.ayaka.io_models.yaml
│ │ ├── kustomization.yaml
│ │ └── kustomizeconfig.yaml
│ ├── default/
│ │ ├── kustomization.yaml
│ │ ├── manager_auth_proxy_patch.yaml
│ │ └── manager_config_patch.yaml
│ ├── manager/
│ │ ├── kustomization.yaml
│ │ └── manager.yaml
│ ├── prometheus/
│ │ ├── kustomization.yaml
│ │ └── monitor.yaml
│ ├── rbac/
│ │ ├── auth_proxy_client_clusterrole.yaml
│ │ ├── auth_proxy_role.yaml
│ │ ├── auth_proxy_role_binding.yaml
│ │ ├── auth_proxy_service.yaml
│ │ ├── kustomization.yaml
│ │ ├── leader_election_role.yaml
│ │ ├── leader_election_role_binding.yaml
│ │ ├── model_editor_role.yaml
│ │ ├── model_viewer_role.yaml
│ │ ├── role.yaml
│ │ ├── role_binding.yaml
│ │ └── service_account.yaml
│ └── samples/
│ ├── kustomization.yaml
│ └── ollama_v1_model.yaml
├── cspell.config.yaml
├── docs/
│ ├── .editorconfig
│ ├── .vitepress/
│ │ ├── config.mts
│ │ └── theme/
│ │ ├── components/
│ │ │ ├── GettingStartedBlocksEn.vue
│ │ │ ├── GettingStartedBlocksZhCn.vue
│ │ │ ├── TitleBlockContainer.vue
│ │ │ └── TitleBlockContainerGroup.vue
│ │ ├── index.mts
│ │ └── style.css
│ ├── eslint.config.js
│ ├── package.json
│ ├── pages/
│ │ ├── en/
│ │ │ ├── acknowledgements.md
│ │ │ ├── guide/
│ │ │ │ ├── getting-started/
│ │ │ │ │ ├── cli.md
│ │ │ │ │ ├── crd.md
│ │ │ │ │ └── index.md
│ │ │ │ ├── overview.md
│ │ │ │ └── supported-models.md
│ │ │ ├── index.md
│ │ │ ├── references/
│ │ │ │ ├── architectural-design.md
│ │ │ │ ├── cli/
│ │ │ │ │ ├── commands/
│ │ │ │ │ │ ├── deploy.md
│ │ │ │ │ │ ├── expose.md
│ │ │ │ │ │ └── undeploy.md
│ │ │ │ │ └── index.md
│ │ │ │ └── crd/
│ │ │ │ ├── index.md
│ │ │ │ └── model.md
│ │ │ └── snippets/
│ │ │ ├── deploy-kubernetes-cluster-with-kind.md
│ │ │ └── install-ollama-operator.md
│ │ └── zh-CN/
│ │ ├── acknowledgements.md
│ │ ├── guide/
│ │ │ ├── getting-started/
│ │ │ │ ├── cli.md
│ │ │ │ ├── crd.md
│ │ │ │ └── index.md
│ │ │ ├── overview.md
│ │ │ └── supported-models.md
│ │ ├── index.md
│ │ ├── references/
│ │ │ ├── architectural-design.md
│ │ │ ├── cli/
│ │ │ │ ├── commands/
│ │ │ │ │ ├── deploy.md
│ │ │ │ │ ├── expose.md
│ │ │ │ │ └── undeploy.md
│ │ │ │ └── index.md
│ │ │ └── crd/
│ │ │ ├── index.md
│ │ │ └── model.md
│ │ └── snippets/
│ │ ├── deploy-kubernetes-cluster-with-kind.md
│ │ └── install-ollama-operator.md
│ ├── public/
│ │ ├── _redirects
│ │ ├── browserconfig.xml
│ │ ├── demo-full.cast
│ │ ├── demo.cast
│ │ └── site.webmanifest
│ ├── shim.d.ts
│ ├── tsconfig.json
│ ├── uno.config.ts
│ └── vite.config.mts
├── go.mod
├── go.sum
├── hack/
│ ├── boilerplate.go.txt
│ ├── kind-config.yaml
│ ├── ollama-model-llama2-kind-cluster.yaml
│ ├── ollama-model-llama2-nfs.yaml
│ ├── ollama-model-phi-kind-cluster.yaml
│ └── ollama-model-phi-nfs.yaml
├── internal/
│ ├── cli/
│ │ └── kollama/
│ │ ├── cmd.go
│ │ ├── cmd_deploy.go
│ │ ├── cmd_expose.go
│ │ ├── cmd_undeploy.go
│ │ ├── common.go
│ │ └── wait_until.go
│ └── controller/
│ └── model_controller.go
└── pkg/
├── model/
│ ├── image_store.go
│ ├── model.go
│ ├── model_test.go
│ ├── pod.go
│ ├── pod_test.go
│ └── recorder.go
└── operator/
└── reconcile.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
# Ignore build and test binaries.
bin/
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: [nekomeowww]
# patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
# otechie: # Replace with a single Otechie username
# lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
================================================
FILE: .github/renovate.json
================================================
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"automerge": true,
"extends": [
"config:recommended",
":dependencyDashboard",
":semanticPrefixFixDepsChoreOthers",
":prHourlyLimitNone",
":prConcurrentLimitNone",
":ignoreModulesAndTests",
"schedule:weekly",
"group:allNonMajor",
"replacements:all",
"workarounds:all"
]
}
================================================
FILE: .github/workflows/ci.yaml
================================================
name: CI
on:
push:
paths-ignore:
- 'docs/pages/**'
branches:
- main
pull_request:
paths-ignore:
- 'docs/pages/**'
branches:
- main
env:
STORE_PATH: ''
jobs:
build_test:
name: Build Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: "^1.25"
cache: true
- name: Test Build
run: go build -v ./...
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v6
with:
go-version: "^1.25"
cache: true
- uses: actions/checkout@v6
- name: golangci-lint
uses: golangci/golangci-lint-action@v9.2.0
with:
args: --timeout=10m
unittest:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: "^1.25"
cache: true
- name: Unit tests
run: |
go test ./... -coverprofile=coverage.out -covermode=atomic
go tool cover -func coverage.out
================================================
FILE: .github/workflows/pr-docs-build.yaml
================================================
name: Build PR Previewing Docs
on:
pull_request:
branches:
- main
paths:
- 'docs/**'
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest]
name: Build - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
steps:
# This is quite weird.
# Even though this is the *intended* solution introduces in official blog post here
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
# But still, as https://github.com/orgs/community/discussions/25220#discussioncomment-7856118 stated,
# this is vulnerable since there is no source of truth about which PR in the triggered workflow.
- name: Persist PR number
run: |
echo "${{ github.event.number }}" > pr_num
- name: Persist branch name
run: |
echo "${{ github.head_ref }}" > branch_name
- name: Upload PR artifact
uses: actions/upload-artifact@v7
with:
name: pr-num
path: ./pr_num
overwrite: true
- name: Upload PR artifact
uses: actions/upload-artifact@v7
with:
name: branch-name
path: ./branch_name
overwrite: true
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: pnpm/action-setup@v4
with:
run_install: false
package_json_file: docs/package.json
- uses: actions/setup-node@v6
with:
cache: pnpm
node-version: latest
registry-url: https://registry.npmjs.org
cache-dependency-path: 'docs/pnpm-lock.yaml'
- working-directory: docs
run: pnpm install --frozen-lockfile
- working-directory: docs
run: pnpm docs:build
env:
# As suggested in Verbose Build option to be able to track down errors https://github.com/vuejs/vitepress/issues/422
# vitepress build command does not have --debug option, so we need to set it manually where the debug package is used.
# DEBUG: 'vitepress:*'
VUE_PROD_HYDRATION_MISMATCH_DETAILS_FLAG: '1'
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: docs-${{ matrix.os }}-build
path: docs/.vitepress/dist
overwrite: true
================================================
FILE: .github/workflows/pr-docs-deployment.yaml
================================================
name: Push PR Previewing Docs to Cloudflare Pages
on:
workflow_run:
workflows:
- Build PR Previewing Docs
types:
- completed
env:
PR_NUM: 0
BRANCH_NAME: main
jobs:
on-success:
name: Deploy to Cloudflare Pages
runs-on: ubuntu-latest
permissions:
pull-requests: write
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Download artifact - PR
uses: dawidd6/action-download-artifact@v18
with:
workflow_conclusion: success
run_id: ${{ github.event.workflow_run.id }}
name: pr-num
path: pr-num
allow_forks: true
- name: Download artifact - PR
uses: dawidd6/action-download-artifact@v18
with:
workflow_conclusion: success
run_id: ${{ github.event.workflow_run.id }}
name: branch-name
path: branch-name
allow_forks: true
- name: Obtain PR number
id: pr-num
run: |
echo "PR_NUM=$(cat pr-num/pr_num)" >> $GITHUB_ENV
- name: Obtain branch name
id: branch-name
run: |
echo "BRANCH_NAME=$(cat branch-name/branch_name)" >> $GITHUB_ENV
- name: Download artifact - Ubuntu
uses: dawidd6/action-download-artifact@v18
with:
workflow_conclusion: success
run_id: ${{ github.event.workflow_run.id }}
name: docs-ubuntu-latest-build
path: docs-ubuntu-latest-build
allow_forks: true
- name: Publish to Cloudflare Pages
id: deploy
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: ${{ secrets.CLOUDFLARE_PROJECT_NAME }}
directory: docs-ubuntu-latest-build
# Optional: Switch what branch you are publishing to.
# By default this will be the branch which triggered this workflow
branch: ${{ env.BRANCH_NAME }}
# Optional: Change the Wrangler version, allows you to point to a specific version or a tag such as `beta`
wranglerVersion: '3'
- name: Find Comment
uses: peter-evans/find-comment@v4
id: fc
with:
issue-number: ${{ env.PR_NUM }}
comment-author: 'github-actions[bot]'
body-includes: to Cloudflare Pages
- name: Create or update comment
uses: peter-evans/create-or-update-comment@v5
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ env.PR_NUM }}
body: |
## ✅ Successfully deployed to Cloudflare Pages
| Status | URL |
|:------------|:-----------------------------------|
| Success | ${{ steps.deploy.outputs.url }} |
edit-mode: replace
on-failure:
name: Failed to build previewing docs
runs-on: ubuntu-latest
permissions:
pull-requests: write
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
steps:
- name: Download artifact - PR
uses: dawidd6/action-download-artifact@v18
with:
workflow_conclusion: success
run_id: ${{ github.event.workflow_run.id }}
name: pr-num
path: pr-num
allow_forks: true
- name: Obtain PR number
id: pr-num
run: |
echo "PR_NUM=$(cat pr-num/pr_num)" >> $GITHUB_ENV
- name: Find Comment
uses: peter-evans/find-comment@v4
id: fc
with:
issue-number: ${{ env.PR_NUM }}
comment-author: 'github-actions[bot]'
body-includes: to Cloudflare Pages
- name: Create or update comment
uses: peter-evans/create-or-update-comment@v5
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ env.PR_NUM }}
body: |
## ❌ Failed to deploy to Cloudflare Pages
| Platform | Status | URL |
|:---------|:------------|:------------------------------------------------------|
| Ubuntu | Failed | Please check the status and logs of the workflow run. |
| Windows | Failed | Please check the status and logs of the workflow run. |
edit-mode: replace
================================================
FILE: .github/workflows/production-docs-deployment.yaml
================================================
name: Build Docs to Cloudflare Pages
on:
push:
branches:
- 'main'
jobs:
build:
name: Build
runs-on: ubuntu-latest
environment:
name: Production Docs
url: https://ollama-operator.ayaka.io
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: pnpm/action-setup@v4
with:
run_install: false
package_json_file: docs/package.json
- uses: actions/setup-node@v6
with:
cache: pnpm
node-version: latest
registry-url: https://registry.npmjs.org
cache-dependency-path: 'docs/pnpm-lock.yaml'
- working-directory: docs
run: pnpm install --frozen-lockfile
- working-directory: docs
run: pnpm docs:build
env:
# As suggested in Verbose Build option to be able to track down errors https://github.com/vuejs/vitepress/issues/422
# vitepress build command does not have --debug option, so we need to set it manually where the debug package is used.
# DEBUG: 'vitepress:*'
VUE_PROD_HYDRATION_MISMATCH_DETAILS_FLAG: '1'
- name: Publish to Cloudflare Pages
id: deploy
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: ${{ secrets.CLOUDFLARE_PROJECT_NAME }}
directory: docs/.vitepress/dist
# Optional: Switch what branch you are publishing to.
# By default this will be the branch which triggered this workflow
branch: main
# Optional: Change the Wrangler version, allows you to point to a specific version or a tag such as `beta`
wranglerVersion: '3'
================================================
FILE: .github/workflows/release-build.yml
================================================
name: Release Build
on:
push:
tags:
- '**'
workflow_dispatch:
jobs:
goreleaser:
name: kollama - Build for GitHub Releases
permissions:
contents: write
packages: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: '1.26'
cache: true
- name: GoReleaser
uses: goreleaser/goreleaser-action@v7
with:
version: latest
args: release --clean --skip=validate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update new version in krew-index
uses: rajatjindal/krew-release-bot@v0.0.51
ghcr_build:
name: ollama-operator - Build for ghcr.io
permissions:
packages: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Fetch version
id: version
run: |
export LAST_TAGGED_COMMIT=$(git rev-list --tags --max-count=1)
export LAST_TAG=$(git describe --tags $LAST_TAGGED_COMMIT)
echo "version=${LAST_TAG#v}" >> $GITHUB_OUTPUT
- # Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action
name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
with:
platforms: linux/amd64,linux/arm64
- name: Sign in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create image tags
id: dockerinfo
run: |
echo "taglatest=ghcr.io/${{ github.repository }}:latest" >> $GITHUB_OUTPUT
echo "tag=ghcr.io/${{ github.repository }}:${{ steps.version.outputs.version }}" >> $GITHUB_OUTPUT
- name: Build and Push
uses: docker/build-push-action@v7
with:
platforms: linux/amd64,linux/arm64
context: ./
file: ./Dockerfile
push: true
no-cache: false
tags: |
${{ steps.dockerinfo.outputs.taglatest }}
${{ steps.dockerinfo.outputs.tag }}
- name: Build installer
run: |
make build-installer IMG=ghcr.io/${{ github.repository }}:${{ steps.version.outputs.version }}
- name: Upload installer
uses: actions/upload-artifact@v7
with:
name: ollama-operator-installer-${{ steps.version.outputs.version }}
path: dist/install.yaml
================================================
FILE: .github/workflows/unstable-build.yml
================================================
name: Unstable Build
on:
workflow_dispatch:
jobs:
ghcr_build:
name: Build for GitHub Container Registry
permissions:
packages: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- # Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action
name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
with:
platforms: linux/amd64,linux/arm64
- name: Sign in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create image tags
id: dockerinfo
run: |
echo "tagunstable=ghcr.io/${{ github.repository }}:unstable" >> $GITHUB_OUTPUT
- name: Build and Push
uses: docker/build-push-action@v7
with:
platforms: linux/amd64,linux/arm64
context: ./
file: ./Dockerfile
push: true
no-cache: false
tags: |
${{ steps.dockerinfo.outputs.tagunstable }}
- name: Build installer
run: |
make build-installer IMG=ghcr.io/${{ github.repository }}:unstable
- name: Upload installer
uses: actions/upload-artifact@v7
with:
name: ollama-operator-installer-unstable
path: dist/install.yaml
================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin/*
Dockerfile.cross
# Built application files
!dist/install.yaml
dist/
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Go workspace file
go.work
# Kubernetes Generated files - skip generated files, except for vendored files
!vendor/**/zz_generated.*
# editor and IDE paraphernalia
.idea
!.vscode/settings.json
*.swp
*.swo
*~
.obsidian/
# Node.js related
.eslintcache
.npmrc
node_modules/
# Vite.js related
.temp
.vite-inspect
# Vitepress related
**/.vitepress/dist/
**/.vitepress/cache/
# Netlify related
**/.netlify/*
**/.netlify/functions-serve/*
================================================
FILE: .golangci.yml
================================================
version: "2"
run:
allow-parallel-runners: true
linters:
default: all
disable:
- containedctx
- contextcheck
- cyclop
- depguard
- err113
- exhaustruct
- funlen
- gochecknoglobals
- gochecknoinits
- gocognit
- gocyclo
- godot
- godox
- ireturn
- lll
- maintidx
- mnd
- nilnil
- nlreturn
- paralleltest
- tagalign
- tagliatelle
- testpackage
- varnamelen
- wrapcheck
- noinlineerr
settings:
dupl:
threshold: 1000
gocritic:
disabled-checks:
- ifElseChain
gosec:
excludes:
- G115
mnd:
ignored-files:
- examples/.*
ignored-functions:
- context.WithTimeout
- strconv.ParseComplex
nestif:
min-complexity: 9
revive:
rules:
- name: blank-imports
disabled: true
wsl_v5:
allow-first-in-block: true
allow-whole-block: false
branch-max-lines: 2
enable:
- assign-expr
disable:
- append
- decl
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- perfsprint
path: _test\.go
- linters:
- forbidigo
path: internal\/cli\/.*\.go
- path: (.+)\.go$
text: if statements should only be cuddled with assignments
- path: (.+)\.go$
text: if statements should only be cuddled with assignments used in the if statement itself
- path: (.+)\.go$
text: assignments should only be cuddled with other assignments
- path: (.+)\.go$
text: declarations should never be cuddled
- path: (.+)\.go$
text: block should not end with a whitespace
paths:
- apis
- api
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- apis
- api
- third_party$
- builtin$
- examples$
================================================
FILE: .goreleaser.yml
================================================
project_name: kollama
release:
github:
owner: nekomeowww
name: ollama-operator
builds:
- id: kollama
goos:
- linux
- windows
- darwin
goarch:
- arm64
- amd64
- "386"
env:
- CGO_ENABLED=0
- GO111MODULE=on
main: cmd/kollama/main.go
archives:
- id: kollama
builds:
- kollama
name_template: "{{ .ProjectName }}_{{ .Tag }}_{{ .Os }}_{{ .Arch }}"
format_overrides:
- goos: windows
format: zip
================================================
FILE: .krew.yaml
================================================
apiVersion: krew.googlecontainertools.github.com/v1alpha2
kind: Plugin
metadata:
name: kollama
spec:
version: {{ .TagName }}
homepage: https://github.com/nekomeowww/ollama-operator
platforms:
- selector:
matchLabels:
os: darwin
arch: amd64
{{addURIAndSha "https://github.com/nekomeowww/ollama-operator/releases/download/{{ .TagName }}/kollama_{{ .TagName }}_darwin_amd64.tar.gz" .TagName }}
bin: kollama
- selector:
matchLabels:
os: darwin
arch: arm64
{{addURIAndSha "https://github.com/nekomeowww/ollama-operator/releases/download/{{ .TagName }}/kollama_{{ .TagName }}_darwin_arm64.tar.gz" .TagName }}
bin: kollama
- selector:
matchLabels:
os: linux
arch: amd64
{{addURIAndSha "https://github.com/nekomeowww/ollama-operator/releases/download/{{ .TagName }}/kollama_{{ .TagName }}_linux_amd64.tar.gz" .TagName }}
bin: kollama
- selector:
matchLabels:
os: linux
arch: arm64
{{addURIAndSha "https://github.com/nekomeowww/ollama-operator/releases/download/{{ .TagName }}/kollama_{{ .TagName }}_linux_arm64.tar.gz" .TagName }}
bin: kollama
- selector:
matchLabels:
os: windows
arch: amd64
{{addURIAndSha "https://github.com/nekomeowww/ollama-operator/releases/download/{{ .TagName }}/kollama_{{ .TagName }}_windows_amd64.zip" .TagName }}
bin: kollama.exe
shortDescription: Interact with the Ollama Operator
description: |
Usage:
kubectl kollama deploy llama2
This plugin will help you to interact with the Ollama Operator to deploy any LLM (Llama Language Model) to your Kubernetes cluster.
Read more documentation at: https://github.com/nekomeowww/ollama-operator
================================================
FILE: .tool-versions
================================================
golang 1.26.1
golangci-lint 2.11.3
================================================
FILE: .vscode/settings.json
================================================
{
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
// The following is optional.
// It's better to put under project setting `.vscode/settings.json`
// to avoid conflicts with working with different eslint configs
// that does not support all formats.
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"json",
"jsonc",
],
}
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Ollama Operator
### Prerequisites
- `go` version `v1.24.0+`
- `docker` version `17.03+`.
- `kubectl` version `v1.11.3+`.
- Access to a Kubernetes `v1.11.3+` cluster (Either kind, minikube is suitable for local development).
## Development
### Develop with `kind`
We have pre-defined `kind` configurations in the `hack` directory to help you get started with the development environment.
> [!NOTE]
> Install kind if you haven't already. You can install it using the following command:
>
> ```shell
> go install sigs.k8s.io/kind@latest
> ```
To create a `kind` cluster with the configurations defined in `hack/kind-config.yaml`, run the following command:
```sh
kind create cluster --config hack/kind-config.yaml
```
### Test controller locally
#### Build and install CRD to local cluster
```shell
make manifests && make install
```
#### Run the controller locally
```shell
make run
```
#### Create a CRD to test the controller
```shell
kubectl apply -f hack/ollama-model-phi-kind-cluster.yaml
```
#### Verify the resources is reconciling
```shell
kubectl describe models
```
## Deployment
### To Deploy on the cluster
**Build and push your image to the location specified by `IMG`:**
```sh
make docker-build docker-push IMG=<some-registry>/ollama-operator:tag
```
> [!NOTE]
> This image ought to be published in the personal registry you specified.
> And it is required to have access to pull the image from the working environment.
> Make sure you have the proper permission to the registry if the above commands don’t work.
**Install the CRDs into the cluster:**
```sh
make install
```
**Deploy the Manager to the cluster with the image specified by `IMG`:**
```sh
make deploy IMG=<some-registry>/ollama-operator:tag
```
> [!NOTE]
> If you encounter RBAC errors, you may need to grant yourself cluster-admin
> privileges or be logged in as admin.
**Create instances of your solution**
You can apply the samples (examples) from the config/sample:
```sh
kubectl apply -k config/samples/
```
> [!NOTE]
> Ensure that the samples has default values to test it out.
### To Uninstall
**Delete the instances (CRs) from the cluster:**
```sh
kubectl delete -k config/samples/
```
**Delete the APIs(CRDs) from the cluster:**
```sh
make uninstall
```
**UnDeploy the controller from the cluster:**
```sh
make undeploy
```
> [!NOTE]
> Run `make help` for more information on all potential `make` targets
## Project Distribution
### Test your build locally
Developers should test their builds locally before pushing the changes to the repository.
#### Test the build of `kollama` locally
This reporsitory has been configured to build and release by using [GoReleaser](https://goreleaser.com/):
> [!NOTE]
> Install GoReleaser if you haven't already by going through the steps in [GoReleaser Install](https://goreleaser.com/install/)
```shell
goreleaser release --snapshot --clean
```
#### Test the build of `ollama-operator` locally
To build the image for `ollama-operator` locally, run the following command:
```shell
docker buildx build --platform linux/amd64,linux/arm64 .
```
#### Test the release of `kollama` to `krew` locally
Please replace `<Your Tag>` with the tag you want to release.
```shell
docker run -v $(pwd)/.krew.yaml:/tmp/template-file.yaml ghcr.io/rajatjindal/krew-release-bot:v0.0.46 krew-release-bot template --tag <Your Tag> --template-file /tmp/template-file.yaml
```
### Build and distribute the project
Following are the steps to build the installer and distribute this project to users.
1. Build the installer for the image built and published in the registry:
```sh
make build-installer IMG=<some-registry>/ollama-operator:tag
```
NOTE: The makefile target mentioned above generates an 'install.yaml'
file in the dist directory. This file contains all the resources built
with Kustomize, which are necessary to install this project without
its dependencies.
2. Using the installer
Users can just run `kubectl apply -f <URL for YAML BUNDLE>` to install the project, i.e.:
```sh
kubectl apply -f https://raw.githubusercontent.com/<org>/ollama-operator/<tag or branch>/dist/install.yaml
```
================================================
FILE: Dockerfile
================================================
# Build the manager binary
FROM golang:1.26 AS builder
ARG TARGETOS
ARG TARGETARCH
WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download
# Copy the go source
COPY cmd/ cmd/
COPY api/ api/
COPY internal/ internal/
COPY pkg/ pkg/
# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN go env -w CGO_ENABLED=0
RUN go env -w GOOS=${TARGETOS:-linux}
RUN go env -w GOARCH=${TARGETARCH}
RUN go build -a -o manager cmd/ollama-operator/main.go
RUN go build -a -o kollama cmd/kollama/main.go
# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
COPY --from=builder /workspace/kollama .
USER 65532:65532
ENTRYPOINT ["/manager"]
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Makefile
================================================
# Image URL to use all building/pushing image targets
IMG ?= ghcr.io/nekomeowww/ollama-operator:0.10.7
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.32.0
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif
# CONTAINER_TOOL defines the container tool to be used for building images.
# Be aware that the target commands are only tested with Docker which is
# scaffolded by default. However, you might want to replace it to use other
# tools. (i.e. podman)
CONTAINER_TOOL ?= docker
# Setting SHELL to bash allows bash commands to be executed by recipes.
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec
.PHONY: all
all: build
##@ General
# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk command is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI control characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
##@ Development
.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...
.PHONY: vet
vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
go test ./test/e2e/ -v -ginkgo.v
.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter & yamllint
$(GOLANGCI_LINT) run
.PHONY: lint-fix
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
$(GOLANGCI_LINT) run --fix
##@ Build
.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
go build -o bin/manager cmd/ollama-operator/main.go
go build -o bin/kollama cmd/kollama/main.go
.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./cmd/ollama-operator/main.go
# If you wish to build the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
.PHONY: docker-build
docker-build: ## Build docker image with the manager.
$(CONTAINER_TOOL) build -t ${IMG} .
.PHONY: docker-push
docker-push: ## Push docker image with the manager.
$(CONTAINER_TOOL) push ${IMG}
# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
.PHONY: docker-buildx
docker-buildx: ## Build and push docker image for the manager for cross-platform support
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
- $(CONTAINER_TOOL) buildx create --name project-v3-builder
$(CONTAINER_TOOL) buildx use project-v3-builder
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
- $(CONTAINER_TOOL) buildx rm project-v3-builder
rm Dockerfile.cross
.PHONY: build-installer
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default > dist/install.yaml
##@ Deployment
ifndef ignore-not-found
ignore-not-found = false
endif
.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/crd | $(KUBECTL) apply --server-side=true -f -
.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default | $(KUBECTL) apply --server-side=true -f -
.PHONY: undeploy
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
##@ Dependencies
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)
## Tool Binaries
KUBECTL ?= kubectl
KUSTOMIZE ?= $(LOCALBIN)/kustomize-$(KUSTOMIZE_VERSION)
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION)
ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION)
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION)
## Tool Versions
KUSTOMIZE_VERSION ?= v5.6.0
CONTROLLER_TOOLS_VERSION ?= v0.17.2
ENVTEST_VERSION ?= release-0.20
GOLANGCI_LINT_VERSION ?= v1.63.4
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))
.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))
.PHONY: envtest
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
$(ENVTEST): $(LOCALBIN)
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,${GOLANGCI_LINT_VERSION})
# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary (ideally with version)
# $2 - package url which can be installed
# $3 - specific version of package
define go-install-tool
@[ -f $(1) ] || { \
set -e; \
package=$(2)@$(3) ;\
echo "Downloading $${package}" ;\
GOBIN=$(LOCALBIN) go install $${package} ;\
mv "$$(echo "$(1)" | sed "s/-$(3)$$//")" $(1) ;\
}
endef
================================================
FILE: PROJECT
================================================
# Code generated by tool. DO NOT EDIT.
# This file is used to track the info used to scaffold your project
# and allow the plugins properly work.
# More info: https://book.kubebuilder.io/reference/project-config.html
domain: ayaka.io
layout:
- go.kubebuilder.io/v4
projectName: ollama-operator
repo: github.com/nekomeowww/ollama-operator
resources:
- api:
crdVersion: v1
namespaced: true
controller: true
domain: ayaka.io
group: ollama
kind: Model
path: github.com/nekomeowww/ollama-operator/api/v1
version: v1
version: "3"
================================================
FILE: README.md
================================================
<div align="center">
<img alt="ollama" height="200px" src="./docs/public/logo.png">
</div>
# Ollama Operator
[](https://discord.gg/ollama)
> Yet another operator for running large language models on Kubernetes with ease. 🙀
>
> Powered by **[Ollama](https://github.com/ollama/ollama)**! 🐫
While [Ollama](https://github.com/ollama/ollama) is a powerful tool for running large language models locally, and the user experience of CLI is just the same as using Docker CLI, it's not possible yet to replicate the same user experience on Kubernetes, especially when it comes to running multiple models on the same cluster with loads of resources and configurations.
That's where the Ollama Operator kicks in:
- Install the operator on your Kubernetes cluster
- Apply the needed CRDs
- Create your models
- Wait for the models to be fetched and loaded, that's it!
Thanks to the great works of [llama.cpp](https://github.com/ggerganov/llama.cpp), **no more worries about Python environment, CUDA drivers.**
The journey to large language models, AIGC, localized agents, [🦜🔗 Langchain](https://www.langchain.com/) and more is just a few steps away!
## Features
- ✅ Abilities to run multiple models on the same cluster.
- ✅ Compatible with all Ollama models, APIs, and CLI.
- ✅ Able to run on [general Kubernetes clusters](https://kubernetes.io/), [K3s clusters](https://k3s.io/) (Respberry Pi, TrueNAS SCALE, etc.), [kind](https://kind.sigs.k8s.io/), [minikube](https://minikube.sigs.k8s.io/docs/), etc. You name it!
- ✅ Easy to install, uninstall, and upgrade.
- ✅ Pull image once, share across the entire node (just like normal images).
- ✅ Easy to expose with existing Kubernetes services, ingress, etc.
- ✅ Doesn't require any additional dependencies, just Kubernetes
## Getting started
### Install operator
```shell
kubectl apply \
--server-side=true \
-f https://raw.githubusercontent.com/nekomeowww/ollama-operator/v0.10.1/dist/install.yaml
```
### Wait for the operator to be ready
```shell
kubectl wait \
-n ollama-operator-system \
--for=jsonpath='{.status.readyReplicas}'=1 \
deployment/ollama-operator-controller-manager
```
### Deploy a model
> [!NOTE]
> You can also use the `kollama` CLI natively shipped by Ollama Operator, and will be easier to interact with the operator.
>
> Install `kollama` CLI:
>
> ```shell
> go install github.com/nekomeowww/ollama-operator/cmd/kollama@latest
> ```
>
> Deploy a model can be done with the following command:
>
> ```shell
> kollama deploy phi --expose --node-port 30001
> ```
>
> More information can be found at [CLI](https://ollama-operator.ayaka.io/pages/en/guide/getting-started/cli.html)
> [!IMPORTANT]
> Working with `kind`?
>
> The default provisioned `StorageClass` in `kind` is `standard`, and will only work with `ReadWriteOnce` access mode, therefore if you would need to run the operator with `kind`, you should specify `persistentVolume` with `accessMode: ReadWriteOnce` in the `Model` CRD:
> ```yaml
> apiVersion: ollama.ayaka.io/v1
> kind: Model
> metadata:
> name: phi
> spec:
> image: phi
> persistentVolume:
> accessMode: ReadWriteOnce
> ```
Let's create a `Model` CR for the model `phi`:
```yaml
apiVersion: ollama.ayaka.io/v1
kind: Model
metadata:
name: phi
spec:
image: phi
```
Apply the `Model` CR to your Kubernetes cluster:
```shell
kubectl apply -f ollama-model-phi.yaml
```
Wait for the model to be ready:
```shell
kubectl wait --for=jsonpath='{.status.readyReplicas}'=1 deployment/ollama-model-phi
```
### Access the model
1. Ready! Now let's forward the ports to access the model:
```shell
kubectl port-forward svc/ollama-model-phi ollama
```
2. Interact with the model:
```shell
ollama run phi
```
### Full options
```yaml
apiVersion: ollama.ayaka.io/v1
kind: Model
metadata:
name: phi
spec:
# Scale the model to 2 replicas
replicas: 2
# Use the model image `phi`
image: phi
imagePullPolicy: IfNotPresent
storageClassName: local-path
# If you have your own PersistentVolumeClaim created
persistentVolumeClaim: your-pvc
# If you need to specify the access mode for the PersistentVolume
persistentVolume:
accessMode: ReadWriteOnce
```
## Supported models
Unlock the abilities to run the following models with the Ollama Operator over Kubernetes:
> [!TIP]
> By the power of [`Modelfile`](https://github.com/ollama/ollama/blob/main/docs/modelfile.md) backed by Ollama, you can create and bundle any of your own model. **As long as it's a GGUF formatted model.**
>
> Full list of available images can be found at [Ollama Library](https://ollama.com/library).
> [!WARNING]
> You should have at least 8 GB of RAM available on your node to run the 7B models, 16 GB to run the 13B models, and 32 GB to run the 33B models.
> [!WARNING]
> The actual size of downloaded large language models are huge by comparing to the size of general container images.
>
> 1. Fast and stable network connection is recommended to download the models.
> 2. Efficient storage is required to store the models if you want to run models larger than 13B.
## Architecture Overview
There are two major components that the Ollama Operator will create for:
1. **Model Inferencing Server**: The model inferencing server is a gRPC server that runs the model and serves the model's API. It is created as a `Deployment` in the Kubernetes cluster.
2. **Model Image Storage**: The model image storage is a `PersistentVolume` that stores the model image. It is created as a `StatefulSet` along with a `PersistentVolumeClaim` in the Kubernetes cluster.
> [!NOTE]
> The image that created by [`Modelfile`](https://github.com/ollama/ollama/blob/main/docs/modelfile.md) of Ollama is a valid OCI format image, however, due to the incompatible `contentType` value, and the overall structure of the `Modelfile` image to the general container image, it's not possible to run the model directly with the general container runtime. Therefore a standalone service/deployment of **Model Image Storage** is required to be persisted on the Kubernetes cluster in order to hold and cache the previously downloaded model image.
The detailed resources it creates, and the relationships between them are shown in the following diagram:
<picture>
<source
srcset="./docs/public/architecture-theme-night.png"
media="(prefers-color-scheme: dark)"
/>
<source
srcset="./docs/public/architecture-theme-day.png"
media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)"
/>
<img src="./docs/public/architecture-theme-day.png" />
</picture>
## Contributing
- Refer to the [CONTRIBUTING.md](CONTRIBUTING.md) for more information.
- More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html)
## Acknowledgements
Gratefully thanks to the following projects and their authors, contributors:
- [Ollama](https://github.com/ollama/ollama)
- [llama.cpp](https://github.com/ggerganov/llama.cpp)
- [Kubebuilder](https://book.kubebuilder.io/introduction.html)
It is because of their hard work and contributions that this program exists.
================================================
FILE: api/ollama/v1/groupversion_info.go
================================================
/*
Copyright 2024.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package v1 contains API Schema definitions for the ollama v1 API group
// +kubebuilder:object:generate=true
// +groupName=ollama.ayaka.io
package v1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)
var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "ollama.ayaka.io", Version: "v1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
================================================
FILE: api/ollama/v1/model_types.go
================================================
/*
Copyright 2024.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type ModelPersistentVolumeSpec struct {
// accessModes contains all ways the volume can be mounted.
// More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes
// +optional
AccessMode *corev1.PersistentVolumeAccessMode `json:"accessMode,omitempty" protobuf:"bytes,1,opt,name=accessMode,casttype=PersistentVolumeAccessMode"`
}
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
// ModelSpec defines the desired state of Model
type ModelSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Number of desired pods. This is a pointer to distinguish between explicit
// zero and not specified. Defaults to 1.
// +optional
Replicas *int32 `json:"replicas,omitempty" protobuf:"varint,1,opt,name=replicas"`
// Container image name.
// More info: https://kubernetes.io/docs/concepts/containers/images
// This field is optional to allow higher level config management to default or override
// container images in workload controllers like Deployments and StatefulSets.
Image string `json:"image" protobuf:"bytes,2,name=image"`
// Image pull policy.
// One of Always, Never, IfNotPresent.
// Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.
// Cannot be updated.
// More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
// +optional
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty" protobuf:"bytes,3,opt,name=imagePullPolicy,casttype=PullPolicy"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use.
// More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod
// +optional
// +patchMergeKey=name
// +patchStrategy=merge
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,4,rep,name=imagePullSecrets"`
// Compute Resources required by this container.
// Cannot be updated.
// More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
// +optional
Resources corev1.ResourceRequirements `json:"resources,omitempty" protobuf:"bytes,5,opt,name=resources"`
// storageClassName is the name of StorageClass to which this persistent volume belongs. Empty value
// means that this volume does not belong to any StorageClass.
// +optional
StorageClassName *string `json:"storageClassName,omitempty" protobuf:"bytes,6,opt,name=storageClassName"`
// persistentVolumeClaimVolumeSource represents a reference to a
// PersistentVolumeClaim in the same namespace.
// More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
// +optional
PersistentVolumeClaim *corev1.PersistentVolumeClaimVolumeSource `json:"persistentVolumeClaim,omitempty" protobuf:"bytes,7,opt,name=persistentVolumeClaim"`
// spec defines a specification of a persistent volume owned by the cluster.
// Provisioned by an administrator.
// More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes
// +optional
PersistentVolume *ModelPersistentVolumeSpec `json:"persistentVolume,omitempty" protobuf:"bytes,8,opt,name=persistentVolume"`
// RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used
// to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run.
// If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an
// empty definition that uses the default runtime handler.
// More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class
// +optional
RuntimeClassName *string `json:"runtimeClassName,omitempty" protobuf:"bytes,9,opt,name=runtimeClassName"`
// List of sources to populate environment variables in the container.
// The keys defined within a source must be a C_IDENTIFIER. All invalid keys
// will be reported as an event when the container is starting. When a key exists in multiple
// sources, the value associated with the last source will take precedence.
// Values defined by an Env with a duplicate key will take precedence.
// Cannot be updated.
// +optional
ExtraEnvFrom []corev1.EnvFromSource `json:"extraEnvFrom,omitempty" protobuf:"bytes,10,rep,name=extraEnvFrom"`
// List of environment variables to set in the container.
// Cannot be updated.
// +optional
// +patchMergeKey=name
// +patchStrategy=merge
Env []corev1.EnvVar `json:"extraEnv,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,11,rep,name=extraEnv"`
// PodTemplateSpec describes the data a pod should have when created from a template
// +optional
PodTemplate *corev1.PodTemplateSpec `json:"podTemplate" protobuf:"bytes,12,opt,name=podTemplate"`
}
type ConditionType string
// These are valid condition statuses. "ConditionTrue" means a resource is in the condition.
// "ConditionFalse" means a resource is not in the condition. "ConditionUnknown" means kubernetes
// can't decide if a resource is in the condition or not. In the future, we could add other
// intermediate conditions, e.g. ConditionDegraded.
const (
ModelUnknown ConditionType = "Unknown"
// Available means the deployment is available, ie. at least the minimum available
// replicas required are up and running for at least minReadySeconds.
ModelAvailable ConditionType = "Available"
// Progressing means the deployment is progressing. Progress for a deployment is
// considered when a new replica set is created or adopted, and when new pods scale
// up or old pods scale down. Progress is not estimated for paused deployments or
// when progressDeadlineSeconds is not specified.
ModelProgressing ConditionType = "Progressing"
// ReplicaFailure is added in a deployment when one of its pods fails to be created
// or deleted.
ModelReplicaFailure ConditionType = "ReplicaFailure"
)
type ModelStatusCondition struct {
// Type of deployment condition.
Type ConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=ConditionType"`
// Status of the condition, one of True, False, Unknown.
Status corev1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=k8s.io/api/core/v1.ConditionStatus"`
// The last time this condition was updated.
LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty" protobuf:"bytes,6,opt,name=lastUpdateTime"`
// Last time the condition transitioned from one status to another.
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,7,opt,name=lastTransitionTime"`
// The reason for the condition's last transition.
Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"`
// A human readable message indicating details about the transition.
Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"`
}
// ModelStatus defines the observed state of Model
type ModelStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Total number of non-terminated pods targeted by this deployment (their labels match the selector).
// +optional
Replicas int32 `json:"replicas,omitempty" protobuf:"varint,2,opt,name=replicas"`
// readyReplicas is the number of pods targeted by this Deployment with a Ready Condition.
// +optional
ReadyReplicas int32 `json:"readyReplicas,omitempty" protobuf:"varint,7,opt,name=readyReplicas"`
// Total number of available pods (ready for at least minReadySeconds) targeted by this deployment.
// +optional
AvailableReplicas int32 `json:"availableReplicas,omitempty" protobuf:"varint,4,opt,name=availableReplicas"`
// Total number of unavailable pods targeted by this deployment. This is the total number of
// pods that are still required for the deployment to have 100% available capacity. They may
// either be pods that are running but not yet available or pods that still have not been created.
// +optional
UnavailableReplicas int32 `json:"unavailableReplicas,omitempty" protobuf:"varint,5,opt,name=unavailableReplicas"`
// +kubebuilder:validation:Optional
Conditions []ModelStatusCondition `json:"conditions,omitempty"`
}
// Model is the Schema for the models API
// +genclient
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Model",type=string,JSONPath=`.spec.image`
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[0].type`
type Model struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ModelSpec `json:"spec,omitempty"`
Status ModelStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// ModelList contains a list of Model
type ModelList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Model `json:"items"`
}
func init() {
SchemeBuilder.Register(&Model{}, &ModelList{})
}
================================================
FILE: api/ollama/v1/zz_generated.deepcopy.go
================================================
//go:build !ignore_autogenerated
/*
Copyright 2024.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1
import (
corev1 "k8s.io/api/core/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Model) DeepCopyInto(out *Model) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Model.
func (in *Model) DeepCopy() *Model {
if in == nil {
return nil
}
out := new(Model)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Model) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ModelList) DeepCopyInto(out *ModelList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Model, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelList.
func (in *ModelList) DeepCopy() *ModelList {
if in == nil {
return nil
}
out := new(ModelList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ModelList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ModelPersistentVolumeSpec) DeepCopyInto(out *ModelPersistentVolumeSpec) {
*out = *in
if in.AccessMode != nil {
in, out := &in.AccessMode, &out.AccessMode
*out = new(corev1.PersistentVolumeAccessMode)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelPersistentVolumeSpec.
func (in *ModelPersistentVolumeSpec) DeepCopy() *ModelPersistentVolumeSpec {
if in == nil {
return nil
}
out := new(ModelPersistentVolumeSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ModelSpec) DeepCopyInto(out *ModelSpec) {
*out = *in
if in.Replicas != nil {
in, out := &in.Replicas, &out.Replicas
*out = new(int32)
**out = **in
}
if in.ImagePullSecrets != nil {
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
*out = make([]corev1.LocalObjectReference, len(*in))
copy(*out, *in)
}
in.Resources.DeepCopyInto(&out.Resources)
if in.StorageClassName != nil {
in, out := &in.StorageClassName, &out.StorageClassName
*out = new(string)
**out = **in
}
if in.PersistentVolumeClaim != nil {
in, out := &in.PersistentVolumeClaim, &out.PersistentVolumeClaim
*out = new(corev1.PersistentVolumeClaimVolumeSource)
**out = **in
}
if in.PersistentVolume != nil {
in, out := &in.PersistentVolume, &out.PersistentVolume
*out = new(ModelPersistentVolumeSpec)
(*in).DeepCopyInto(*out)
}
if in.RuntimeClassName != nil {
in, out := &in.RuntimeClassName, &out.RuntimeClassName
*out = new(string)
**out = **in
}
if in.ExtraEnvFrom != nil {
in, out := &in.ExtraEnvFrom, &out.ExtraEnvFrom
*out = make([]corev1.EnvFromSource, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Env != nil {
in, out := &in.Env, &out.Env
*out = make([]corev1.EnvVar, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.PodTemplate != nil {
in, out := &in.PodTemplate, &out.PodTemplate
*out = new(corev1.PodTemplateSpec)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelSpec.
func (in *ModelSpec) DeepCopy() *ModelSpec {
if in == nil {
return nil
}
out := new(ModelSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ModelStatus) DeepCopyInto(out *ModelStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]ModelStatusCondition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelStatus.
func (in *ModelStatus) DeepCopy() *ModelStatus {
if in == nil {
return nil
}
out := new(ModelStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ModelStatusCondition) DeepCopyInto(out *ModelStatusCondition) {
*out = *in
in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ModelStatusCondition.
func (in *ModelStatusCondition) DeepCopy() *ModelStatusCondition {
if in == nil {
return nil
}
out := new(ModelStatusCondition)
in.DeepCopyInto(out)
return out
}
================================================
FILE: cmd/kollama/main.go
================================================
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"os"
"github.com/spf13/pflag"
"github.com/nekomeowww/ollama-operator/internal/cli/kollama"
"k8s.io/cli-runtime/pkg/genericiooptions"
// Import authentication plugins (Go)
// By default, plugins that use client-go cannot authenticate to Kubernetes clusters on many cloud providers. To address this, include the following import in your plugin:
// from - Best practices · Krew
// https://krew.sigs.k8s.io/docs/developer-guide/develop/best-practices/
_ "k8s.io/client-go/plugin/pkg/client/auth"
)
func main() {
flags := pflag.NewFlagSet("kollama", pflag.ExitOnError)
pflag.CommandLine = flags
root := kollama.NewCmd(genericiooptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr})
err := root.Execute()
if err != nil {
os.Exit(1)
}
}
================================================
FILE: cmd/ollama-operator/main.go
================================================
/*
Copyright 2024.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"crypto/tls"
"flag"
"os"
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/webhook"
ollamav1 "github.com/nekomeowww/ollama-operator/api/ollama/v1"
"github.com/nekomeowww/ollama-operator/internal/controller"
//+kubebuilder:scaffold:imports
)
var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
)
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(ollamav1.AddToScheme(scheme))
//+kubebuilder:scaffold:scheme
}
func main() {
var (
metricsAddr string
enableLeaderElection bool
probeAddr string
secureMetrics bool
enableHTTP2 bool
)
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
flag.BoolVar(&secureMetrics, "metrics-secure", false,
"If set the metrics endpoint is served securely")
flag.BoolVar(&enableHTTP2, "enable-http2", false,
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
opts := zap.Options{
Development: true,
}
opts.BindFlags(flag.CommandLine)
flag.Parse()
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
// if the enable-http2 flag is false (the default), http/2 should be disabled
// due to its vulnerabilities. More specifically, disabling http/2 will
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
// Rapid Reset CVEs. For more information see:
// - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
// - https://github.com/advisories/GHSA-4374-p667-p6c8
disableHTTP2 := func(c *tls.Config) {
setupLog.Info("disabling http/2")
c.NextProtos = []string{"http/1.1"}
}
tlsOpts := []func(*tls.Config){}
if !enableHTTP2 {
tlsOpts = append(tlsOpts, disableHTTP2)
}
webhookServer := webhook.NewServer(webhook.Options{
TLSOpts: tlsOpts,
})
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
Metrics: metricsserver.Options{
BindAddress: metricsAddr,
SecureServing: secureMetrics,
TLSOpts: tlsOpts,
},
WebhookServer: webhookServer,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "300b498d.ayaka.io",
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
// when the Manager ends. This requires the binary to immediately end when the
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
// speeds up voluntary leader transitions as the new leader don't have to wait
// LeaseDuration time first.
//
// In the default scaffold provided, the program ends immediately after
// the manager stops, so would be fine to enable this option. However,
// if you are doing or is intended to do any operation such as perform cleanups
// after the manager stops then its usage might be unsafe.
// LeaderElectionReleaseOnCancel: true,
})
if err != nil {
setupLog.Error(err, "unable to start manager")
os.Exit(1)
}
if err = (&controller.ModelReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("ollama-model-controller"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Model")
os.Exit(1)
}
//+kubebuilder:scaffold:builder
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up health check")
os.Exit(1)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up ready check")
os.Exit(1)
}
setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
}
================================================
FILE: config/crd/bases/ollama.ayaka.io_models.yaml
================================================
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.17.2
name: models.ollama.ayaka.io
spec:
group: ollama.ayaka.io
names:
kind: Model
listKind: ModelList
plural: models
singular: model
scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .spec.image
name: Model
type: string
- jsonPath: .status.conditions[0].type
name: Status
type: string
name: v1
schema:
openAPIV3Schema:
description: Model is the Schema for the models API
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: ModelSpec defines the desired state of Model
properties:
extraEnv:
description: |-
List of environment variables to set in the container.
Cannot be updated.
items:
description: EnvVar represents an environment variable present in
a Container.
properties:
name:
description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string
value:
description: |-
Variable references $(VAR_NAME) are expanded
using the previously defined environment variables in the container and
any service environment variables. If a variable cannot be resolved,
the reference in the input string will be unchanged. Double $$ are reduced
to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.
"$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
Escaped references will never be expanded, regardless of whether the variable
exists or not.
Defaults to "".
type: string
valueFrom:
description: Source for the environment variable's value. Cannot
be used if value is not empty.
properties:
configMapKeyRef:
description: Selects a key of a ConfigMap.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap or its key
must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
fieldRef:
description: |-
Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`,
spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.
properties:
apiVersion:
description: Version of the schema the FieldPath is
written in terms of, defaults to "v1".
type: string
fieldPath:
description: Path of the field to select in the specified
API version.
type: string
required:
- fieldPath
type: object
x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount containing
the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
description: |-
Selects a resource of the container: only resources limits and requests
(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.
properties:
containerName:
description: 'Container name: required for volumes,
optional for env vars'
type: string
divisor:
anyOf:
- type: integer
- type: string
description: Specifies the output format of the exposed
resources, defaults to "1"
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
resource:
description: 'Required: resource to select'
type: string
required:
- resource
type: object
x-kubernetes-map-type: atomic
secretKeyRef:
description: Selects a key of a secret in the pod's namespace
properties:
key:
description: The key of the secret to select from. Must
be a valid secret key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret or its key must
be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
required:
- name
type: object
type: array
extraEnvFrom:
description: |-
List of sources to populate environment variables in the container.
The keys defined within a source must be a C_IDENTIFIER. All invalid keys
will be reported as an event when the container is starting. When a key exists in multiple
sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence.
Cannot be updated.
items:
description: EnvFromSource represents the source of a set of ConfigMaps
or Secrets
properties:
configMapRef:
description: The ConfigMap to select from
properties:
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap must be defined
type: boolean
type: object
x-kubernetes-map-type: atomic
prefix:
description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string
secretRef:
description: The Secret to select from
properties:
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret must be defined
type: boolean
type: object
x-kubernetes-map-type: atomic
type: object
type: array
image:
description: |-
Container image name.
More info: https://kubernetes.io/docs/concepts/containers/images
This field is optional to allow higher level config management to default or override
container images in workload controllers like Deployments and StatefulSets.
type: string
imagePullPolicy:
description: |-
Image pull policy.
One of Always, Never, IfNotPresent.
Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.
Cannot be updated.
More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
type: string
imagePullSecrets:
description: |-
ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
If specified, these secrets will be passed to individual puller implementations for them to use.
More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
type: object
x-kubernetes-map-type: atomic
type: array
persistentVolume:
description: |-
spec defines a specification of a persistent volume owned by the cluster.
Provisioned by an administrator.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes
properties:
accessMode:
description: |-
accessModes contains all ways the volume can be mounted.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes
type: string
type: object
persistentVolumeClaim:
description: |-
persistentVolumeClaimVolumeSource represents a reference to a
PersistentVolumeClaim in the same namespace.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
properties:
claimName:
description: |-
claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
type: string
readOnly:
description: |-
readOnly Will force the ReadOnly setting in VolumeMounts.
Default false.
type: boolean
required:
- claimName
type: object
podTemplate:
description: PodTemplateSpec describes the data a pod should have
when created from a template
properties:
metadata:
description: |-
Standard object's metadata.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
type: object
spec:
description: |-
Specification of the desired behavior of the pod.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
properties:
activeDeadlineSeconds:
description: |-
Optional duration in seconds the pod may be active on the node relative to
StartTime before the system will actively try to mark it failed and kill associated containers.
Value must be a positive integer.
format: int64
type: integer
affinity:
description: If specified, the pod's scheduling constraints
properties:
nodeAffinity:
description: Describes node affinity scheduling rules
for the pod.
properties:
preferredDuringSchedulingIgnoredDuringExecution:
description: |-
The scheduler will prefer to schedule pods to nodes that satisfy
the affinity expressions specified by this field, but it may choose
a node that violates one or more of the expressions. The node that is
most preferred is the one with the greatest sum of weights, i.e.
for each node that meets all of the scheduling requirements (resource
request, requiredDuringScheduling affinity expressions, etc.),
compute a sum by iterating through the elements of this field and adding
"weight" to the sum if the node matches the corresponding matchExpressions; the
node(s) with the highest sum are the most preferred.
items:
description: |-
An empty preferred scheduling term matches all objects with implicit weight 0
(i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).
properties:
preference:
description: A node selector term, associated
with the corresponding weight.
properties:
matchExpressions:
description: A list of node selector requirements
by node's labels.
items:
description: |-
A node selector requirement is a selector that contains values, a key, and an operator
that relates the key and values.
properties:
key:
description: The label key that the
selector applies to.
type: string
operator:
description: |-
Represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
type: string
values:
description: |-
An array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. If the operator is Gt or Lt, the values
array must have a single element, which will be interpreted as an integer.
This array is replaced during a strategic merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchFields:
description: A list of node selector requirements
by node's fields.
items:
description: |-
A node selector requirement is a selector that contains values, a key, and an operator
that relates the key and values.
properties:
key:
description: The label key that the
selector applies to.
type: string
operator:
description: |-
Represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
type: string
values:
description: |-
An array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. If the operator is Gt or Lt, the values
array must have a single element, which will be interpreted as an integer.
This array is replaced during a strategic merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
type: object
x-kubernetes-map-type: atomic
weight:
description: Weight associated with matching
the corresponding nodeSelectorTerm, in the
range 1-100.
format: int32
type: integer
required:
- preference
- weight
type: object
type: array
x-kubernetes-list-type: atomic
requiredDuringSchedulingIgnoredDuringExecution:
description: |-
If the affinity requirements specified by this field are not met at
scheduling time, the pod will not be scheduled onto the node.
If the affinity requirements specified by this field cease to be met
at some point during pod execution (e.g. due to an update), the system
may or may not try to eventually evict the pod from its node.
properties:
nodeSelectorTerms:
description: Required. A list of node selector
terms. The terms are ORed.
items:
description: |-
A null or empty node selector term matches no objects. The requirements of
them are ANDed.
The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
properties:
matchExpressions:
description: A list of node selector requirements
by node's labels.
items:
description: |-
A node selector requirement is a selector that contains values, a key, and an operator
that relates the key and values.
properties:
key:
description: The label key that the
selector applies to.
type: string
operator:
description: |-
Represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
type: string
values:
description: |-
An array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. If the operator is Gt or Lt, the values
array must have a single element, which will be interpreted as an integer.
This array is replaced during a strategic merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchFields:
description: A list of node selector requirements
by node's fields.
items:
description: |-
A node selector requirement is a selector that contains values, a key, and an operator
that relates the key and values.
properties:
key:
description: The label key that the
selector applies to.
type: string
operator:
description: |-
Represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
type: string
values:
description: |-
An array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. If the operator is Gt or Lt, the values
array must have a single element, which will be interpreted as an integer.
This array is replaced during a strategic merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
type: object
x-kubernetes-map-type: atomic
type: array
x-kubernetes-list-type: atomic
required:
- nodeSelectorTerms
type: object
x-kubernetes-map-type: atomic
type: object
podAffinity:
description: Describes pod affinity scheduling rules (e.g.
co-locate this pod in the same node, zone, etc. as some
other pod(s)).
properties:
preferredDuringSchedulingIgnoredDuringExecution:
description: |-
The scheduler will prefer to schedule pods to nodes that satisfy
the affinity expressions specified by this field, but it may choose
a node that violates one or more of the expressions. The node that is
most preferred is the one with the greatest sum of weights, i.e.
for each node that meets all of the scheduling requirements (resource
request, requiredDuringScheduling affinity expressions, etc.),
compute a sum by iterating through the elements of this field and adding
"weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the
node(s) with the highest sum are the most preferred.
items:
description: The weights of all of the matched WeightedPodAffinityTerm
fields are added per-node to find the most preferred
node(s)
properties:
podAffinityTerm:
description: Required. A pod affinity term,
associated with the corresponding weight.
properties:
labelSelector:
description: |-
A label query over a set of resources, in this case pods.
If it's null, this PodAffinityTerm matches with no Pods.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The
requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label
key that the selector applies
to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
matchLabelKeys:
description: |-
MatchLabelKeys is a set of pod label keys to select which pods will
be taken into consideration. The keys are used to lookup values from the
incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
to select the group of existing pods which pods will be taken into consideration
for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set.
items:
type: string
type: array
x-kubernetes-list-type: atomic
mismatchLabelKeys:
description: |-
MismatchLabelKeys is a set of pod label keys to select which pods will
be taken into consideration. The keys are used to lookup values from the
incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
to select the group of existing pods which pods will be taken into consideration
for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
items:
type: string
type: array
x-kubernetes-list-type: atomic
namespaceSelector:
description: |-
A label query over the set of namespaces that the term applies to.
The term is applied to the union of the namespaces selected by this field
and the ones listed in the namespaces field.
null selector and null or empty namespaces list means "this pod's namespace".
An empty selector ({}) matches all namespaces.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The
requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label
key that the selector applies
to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
namespaces:
description: |-
namespaces specifies a static list of namespace names that the term applies to.
The term is applied to the union of the namespaces listed in this field
and the ones selected by namespaceSelector.
null or empty namespaces list and null namespaceSelector means "this pod's namespace".
items:
type: string
type: array
x-kubernetes-list-type: atomic
topologyKey:
description: |-
This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
the labelSelector in the specified namespaces, where co-located is defined as running on a node
whose value of the label with key topologyKey matches that of any node on which any of the
selected pods is running.
Empty topologyKey is not allowed.
type: string
required:
- topologyKey
type: object
weight:
description: |-
weight associated with matching the corresponding podAffinityTerm,
in the range 1-100.
format: int32
type: integer
required:
- podAffinityTerm
- weight
type: object
type: array
x-kubernetes-list-type: atomic
requiredDuringSchedulingIgnoredDuringExecution:
description: |-
If the affinity requirements specified by this field are not met at
scheduling time, the pod will not be scheduled onto the node.
If the affinity requirements specified by this field cease to be met
at some point during pod execution (e.g. due to a pod label update), the
system may or may not try to eventually evict the pod from its node.
When there are multiple elements, the lists of nodes corresponding to each
podAffinityTerm are intersected, i.e. all terms must be satisfied.
items:
description: |-
Defines a set of pods (namely those matching the labelSelector
relative to the given namespace(s)) that this pod should be
co-located (affinity) or not co-located (anti-affinity) with,
where co-located is defined as running on a node whose value of
the label with key <topologyKey> matches that of any node on which
a pod of the set of pods is running
properties:
labelSelector:
description: |-
A label query over a set of resources, in this case pods.
If it's null, this PodAffinityTerm matches with no Pods.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The requirements
are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key
that the selector applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
matchLabelKeys:
description: |-
MatchLabelKeys is a set of pod label keys to select which pods will
be taken into consideration. The keys are used to lookup values from the
incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
to select the group of existing pods which pods will be taken into consideration
for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set.
items:
type: string
type: array
x-kubernetes-list-type: atomic
mismatchLabelKeys:
description: |-
MismatchLabelKeys is a set of pod label keys to select which pods will
be taken into consideration. The keys are used to lookup values from the
incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
to select the group of existing pods which pods will be taken into consideration
for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
items:
type: string
type: array
x-kubernetes-list-type: atomic
namespaceSelector:
description: |-
A label query over the set of namespaces that the term applies to.
The term is applied to the union of the namespaces selected by this field
and the ones listed in the namespaces field.
null selector and null or empty namespaces list means "this pod's namespace".
An empty selector ({}) matches all namespaces.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The requirements
are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key
that the selector applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
namespaces:
description: |-
namespaces specifies a static list of namespace names that the term applies to.
The term is applied to the union of the namespaces listed in this field
and the ones selected by namespaceSelector.
null or empty namespaces list and null namespaceSelector means "this pod's namespace".
items:
type: string
type: array
x-kubernetes-list-type: atomic
topologyKey:
description: |-
This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
the labelSelector in the specified namespaces, where co-located is defined as running on a node
whose value of the label with key topologyKey matches that of any node on which any of the
selected pods is running.
Empty topologyKey is not allowed.
type: string
required:
- topologyKey
type: object
type: array
x-kubernetes-list-type: atomic
type: object
podAntiAffinity:
description: Describes pod anti-affinity scheduling rules
(e.g. avoid putting this pod in the same node, zone,
etc. as some other pod(s)).
properties:
preferredDuringSchedulingIgnoredDuringExecution:
description: |-
The scheduler will prefer to schedule pods to nodes that satisfy
the anti-affinity expressions specified by this field, but it may choose
a node that violates one or more of the expressions. The node that is
most preferred is the one with the greatest sum of weights, i.e.
for each node that meets all of the scheduling requirements (resource
request, requiredDuringScheduling anti-affinity expressions, etc.),
compute a sum by iterating through the elements of this field and subtracting
"weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
node(s) with the highest sum are the most preferred.
items:
description: The weights of all of the matched WeightedPodAffinityTerm
fields are added per-node to find the most preferred
node(s)
properties:
podAffinityTerm:
description: Required. A pod affinity term,
associated with the corresponding weight.
properties:
labelSelector:
description: |-
A label query over a set of resources, in this case pods.
If it's null, this PodAffinityTerm matches with no Pods.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The
requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label
key that the selector applies
to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
matchLabelKeys:
description: |-
MatchLabelKeys is a set of pod label keys to select which pods will
be taken into consideration. The keys are used to lookup values from the
incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
to select the group of existing pods which pods will be taken into consideration
for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set.
items:
type: string
type: array
x-kubernetes-list-type: atomic
mismatchLabelKeys:
description: |-
MismatchLabelKeys is a set of pod label keys to select which pods will
be taken into consideration. The keys are used to lookup values from the
incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
to select the group of existing pods which pods will be taken into consideration
for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
items:
type: string
type: array
x-kubernetes-list-type: atomic
namespaceSelector:
description: |-
A label query over the set of namespaces that the term applies to.
The term is applied to the union of the namespaces selected by this field
and the ones listed in the namespaces field.
null selector and null or empty namespaces list means "this pod's namespace".
An empty selector ({}) matches all namespaces.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The
requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label
key that the selector applies
to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
namespaces:
description: |-
namespaces specifies a static list of namespace names that the term applies to.
The term is applied to the union of the namespaces listed in this field
and the ones selected by namespaceSelector.
null or empty namespaces list and null namespaceSelector means "this pod's namespace".
items:
type: string
type: array
x-kubernetes-list-type: atomic
topologyKey:
description: |-
This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
the labelSelector in the specified namespaces, where co-located is defined as running on a node
whose value of the label with key topologyKey matches that of any node on which any of the
selected pods is running.
Empty topologyKey is not allowed.
type: string
required:
- topologyKey
type: object
weight:
description: |-
weight associated with matching the corresponding podAffinityTerm,
in the range 1-100.
format: int32
type: integer
required:
- podAffinityTerm
- weight
type: object
type: array
x-kubernetes-list-type: atomic
requiredDuringSchedulingIgnoredDuringExecution:
description: |-
If the anti-affinity requirements specified by this field are not met at
scheduling time, the pod will not be scheduled onto the node.
If the anti-affinity requirements specified by this field cease to be met
at some point during pod execution (e.g. due to a pod label update), the
system may or may not try to eventually evict the pod from its node.
When there are multiple elements, the lists of nodes corresponding to each
podAffinityTerm are intersected, i.e. all terms must be satisfied.
items:
description: |-
Defines a set of pods (namely those matching the labelSelector
relative to the given namespace(s)) that this pod should be
co-located (affinity) or not co-located (anti-affinity) with,
where co-located is defined as running on a node whose value of
the label with key <topologyKey> matches that of any node on which
a pod of the set of pods is running
properties:
labelSelector:
description: |-
A label query over a set of resources, in this case pods.
If it's null, this PodAffinityTerm matches with no Pods.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The requirements
are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key
that the selector applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
matchLabelKeys:
description: |-
MatchLabelKeys is a set of pod label keys to select which pods will
be taken into consideration. The keys are used to lookup values from the
incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
to select the group of existing pods which pods will be taken into consideration
for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both matchLabelKeys and labelSelector.
Also, matchLabelKeys cannot be set when labelSelector isn't set.
items:
type: string
type: array
x-kubernetes-list-type: atomic
mismatchLabelKeys:
description: |-
MismatchLabelKeys is a set of pod label keys to select which pods will
be taken into consideration. The keys are used to lookup values from the
incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
to select the group of existing pods which pods will be taken into consideration
for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
pod labels will be ignored. The default value is empty.
The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
items:
type: string
type: array
x-kubernetes-list-type: atomic
namespaceSelector:
description: |-
A label query over the set of namespaces that the term applies to.
The term is applied to the union of the namespaces selected by this field
and the ones listed in the namespaces field.
null selector and null or empty namespaces list means "this pod's namespace".
An empty selector ({}) matches all namespaces.
properties:
matchExpressions:
description: matchExpressions is a list
of label selector requirements. The requirements
are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
properties:
key:
description: key is the label key
that the selector applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
x-kubernetes-list-type: atomic
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
namespaces:
description: |-
namespaces specifies a static list of namespace names that the term applies to.
The term is applied to the union of the namespaces listed in this field
and the ones selected by namespaceSelector.
null or empty namespaces list and null namespaceSelector means "this pod's namespace".
items:
type: string
type: array
x-kubernetes-list-type: atomic
topologyKey:
description: |-
This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
the labelSelector in the specified namespaces, where co-located is defined as running on a node
whose value of the label with key topologyKey matches that of any node on which any of the
selected pods is running.
Empty topologyKey is not allowed.
type: string
required:
- topologyKey
type: object
type: array
x-kubernetes-list-type: atomic
type: object
type: object
automountServiceAccountToken:
description: AutomountServiceAccountToken indicates whether
a service account token should be automatically mounted.
type: boolean
containers:
description: |-
List of containers belonging to the pod.
Containers cannot currently be added or removed.
There must be at least one container in a Pod.
Cannot be updated.
items:
description: A single application container that you want
to run within a pod.
properties:
args:
description: |-
Arguments to the entrypoint.
The container image's CMD is used if this is not provided.
Variable references $(VAR_NAME) are expanded using the container's environment. If a variable
cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced
to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless
of whether the variable exists or not. Cannot be updated.
More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell
items:
type: string
type: array
x-kubernetes-list-type: atomic
command:
description: |-
Entrypoint array. Not executed within a shell.
The container image's ENTRYPOINT is used if this is not provided.
Variable references $(VAR_NAME) are expanded using the container's environment. If a variable
cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced
to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless
of whether the variable exists or not. Cannot be updated.
More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell
items:
type: string
type: array
x-kubernetes-list-type: atomic
env:
description: |-
List of environment variables to set in the container.
Cannot be updated.
items:
description: EnvVar represents an environment variable
present in a Container.
properties:
name:
description: |-
Name of the environment variable.
May consist of any printable ASCII characters except '='.
type: string
value:
description: |-
Variable references $(VAR_NAME) are expanded
using the previously defined environment variables in the container and
any service environment variables. If a variable cannot be resolved,
the reference in the input string will be unchanged. Double $$ are reduced
to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.
"$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
Escaped references will never be expanded, regardless of whether the variable
exists or not.
Defaults to "".
type: string
valueFrom:
description: Source for the environment variable's
value. Cannot be used if value is not empty.
properties:
configMapKeyRef:
description: Selects a key of a ConfigMap.
properties:
key:
description: The key to select.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap
or its key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
fieldRef:
description: |-
Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['<KEY>']`, `metadata.annotations['<KEY>']`,
spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.
properties:
apiVersion:
description: Version of the schema the
FieldPath is written in terms of, defaults
to "v1".
type: string
fieldPath:
description: Path of the field to select
in the specified API version.
type: string
required:
- fieldPath
type: object
x-kubernetes-map-type: atomic
fileKeyRef:
description: |-
FileKeyRef selects a key of the env file.
Requires the EnvFiles feature gate to be enabled.
properties:
key:
description: |-
The key within the env file. An invalid key will prevent the pod from starting.
The keys defined within a source may consist of any printable ASCII characters except '='.
During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
type: string
optional:
default: false
description: |-
Specify whether the file or its key must be defined. If the file or key
does not exist, then the env var is not published.
If optional is set to true and the specified key does not exist,
the environment variable will not be set in the Pod's containers.
If optional is set to false and the specified key does not exist,
an error will be returned during Pod creation.
type: boolean
path:
description: |-
The path within the volume from which to select the file.
Must be relative and may not contain the '..' path or start with '..'.
type: string
volumeName:
description: The name of the volume mount
containing the env file.
type: string
required:
- key
- path
- volumeName
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
description: |-
Selects a resource of the container: only resources limits and requests
(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.
properties:
containerName:
description: 'Container name: required
for volumes, optional for env vars'
type: string
divisor:
anyOf:
- type: integer
- type: string
description: Specifies the output format
of the exposed resources, defaults to
"1"
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
resource:
description: 'Required: resource to select'
type: string
required:
- resource
type: object
x-kubernetes-map-type: atomic
secretKeyRef:
description: Selects a key of a secret in
the pod's namespace
properties:
key:
description: The key of the secret to
select from. Must be a valid secret
key.
type: string
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret
or its key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
required:
- name
type: object
type: array
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
envFrom:
description: |-
List of sources to populate environment variables in the container.
The keys defined within a source may consist of any printable ASCII characters except '='.
When a key exists in multiple
sources, the value associated with the last source will take precedence.
Values defined by an Env with a duplicate key will take precedence.
Cannot be updated.
items:
description: EnvFromSource represents the source of
a set of ConfigMaps or Secrets
properties:
configMapRef:
description: The ConfigMap to select from
properties:
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap
must be defined
type: boolean
type: object
x-kubernetes-map-type: atomic
prefix:
description: |-
Optional text to prepend to the name of each environment variable.
May consist of any printable ASCII characters except '='.
type: string
secretRef:
description: The Secret to select from
properties:
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret must
be defined
type: boolean
type: object
x-kubernetes-map-type: atomic
type: object
type: array
x-kubernetes-list-type: atomic
image:
description: |-
Container image name.
More info: https://kubernetes.io/docs/concepts/containers/images
This field is optional to allow higher level config management to default or override
container images in workload controllers like Deployments and StatefulSets.
type: string
imagePullPolicy:
description: |-
Image pull policy.
One of Always, Never, IfNotPresent.
Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.
Cannot be updated.
More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
type: string
lifecycle:
description: |-
Actions that the management system should take in response to container lifecycle events.
Cannot be updated.
properties:
postStart:
description: |-
PostStart is called immediately after a container is created. If the handler fails,
the container is terminated and restarted according to its restart policy.
Other management of the container blocks until the hook completes.
More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
properties:
exec:
description: Exec specifies a command to execute
in the container.
properties:
command:
description: |-
Command is the command line to execute inside the container, the working directory for the
command is root ('/') in the container's filesystem. The command is simply exec'd, it is
not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use
a shell, you need to explicitly call out to that shell.
Exit status of 0 is treated as live/healthy and non-zero is unhealthy.
items:
type: string
type: array
x-kubernetes-list-type: atomic
type: object
httpGet:
description: HTTPGet specifies an HTTP GET request
to perform.
properties:
host:
description: |-
Host name to connect to, defaults to the pod IP. You probably want to set
"Host" in httpHeaders instead.
type: string
httpHeaders:
description: Custom headers to set in the
request. HTTP allows repeated headers.
items:
description: HTTPHeader describes a custom
header to be used in HTTP probes
properties:
name:
description: |-
The header field name.
This will be canonicalized upon output, so case-variant names will be understood as the same header.
type: string
value:
description: The header field value
type: string
required:
- name
- value
type: object
type: array
x-kubernetes-list-type: atomic
path:
description: Path to access on the HTTP
server.
type: string
port:
anyOf:
- type: integer
- type: string
description: |-
Name or number of the port to access on the container.
Number must be in the range 1 to 65535.
Name must be an IANA_SVC_NAME.
x-kubernetes-int-or-string: true
scheme:
description: |-
Scheme to use for connecting to the host.
Defaults to HTTP.
type: string
required:
- port
type: object
sleep:
description: Sleep represents a duration that
the container should sleep.
properties:
seconds:
description: Seconds is the number of seconds
to sleep.
format: int64
type: integer
required:
- seconds
type: object
tcpSocket:
description: |-
Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept
for backward compatibility. There is no validation of this field and
lifecycle hooks will fail at runtime when it is specified.
properties:
host:
description: 'Optional: Host name to connect
to, defaults to the pod IP.'
type: string
port:
anyOf:
- type: integer
- type: string
description: |-
Number or name of the port to access on the container.
Number must be in the range 1 to 65535.
Name must be an IANA_SVC_NAME.
x-kubernetes-int-or-string: true
required:
- port
type: object
type: object
preStop:
description: |-
PreStop is called immediately before a container is terminated due to an
API request or management event such as liveness/startup probe failure,
preemption, resource contention, etc. The handler is not called if the
container crashes or exits. The Pod's termination grace period countdown begins before the
PreStop hook is executed. Regardless of the outcome of the handler, the
container will eventually terminate within the Pod's termination grace
gitextract_tcznvur4/
├── .dockerignore
├── .github/
│ ├── FUNDING.yml
│ ├── renovate.json
│ └── workflows/
│ ├── ci.yaml
│ ├── pr-docs-build.yaml
│ ├── pr-docs-deployment.yaml
│ ├── production-docs-deployment.yaml
│ ├── release-build.yml
│ └── unstable-build.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yml
├── .krew.yaml
├── .tool-versions
├── .vscode/
│ └── settings.json
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── PROJECT
├── README.md
├── api/
│ └── ollama/
│ └── v1/
│ ├── groupversion_info.go
│ ├── model_types.go
│ └── zz_generated.deepcopy.go
├── cmd/
│ ├── kollama/
│ │ └── main.go
│ └── ollama-operator/
│ └── main.go
├── config/
│ ├── crd/
│ │ ├── bases/
│ │ │ └── ollama.ayaka.io_models.yaml
│ │ ├── kustomization.yaml
│ │ └── kustomizeconfig.yaml
│ ├── default/
│ │ ├── kustomization.yaml
│ │ ├── manager_auth_proxy_patch.yaml
│ │ └── manager_config_patch.yaml
│ ├── manager/
│ │ ├── kustomization.yaml
│ │ └── manager.yaml
│ ├── prometheus/
│ │ ├── kustomization.yaml
│ │ └── monitor.yaml
│ ├── rbac/
│ │ ├── auth_proxy_client_clusterrole.yaml
│ │ ├── auth_proxy_role.yaml
│ │ ├── auth_proxy_role_binding.yaml
│ │ ├── auth_proxy_service.yaml
│ │ ├── kustomization.yaml
│ │ ├── leader_election_role.yaml
│ │ ├── leader_election_role_binding.yaml
│ │ ├── model_editor_role.yaml
│ │ ├── model_viewer_role.yaml
│ │ ├── role.yaml
│ │ ├── role_binding.yaml
│ │ └── service_account.yaml
│ └── samples/
│ ├── kustomization.yaml
│ └── ollama_v1_model.yaml
├── cspell.config.yaml
├── docs/
│ ├── .editorconfig
│ ├── .vitepress/
│ │ ├── config.mts
│ │ └── theme/
│ │ ├── components/
│ │ │ ├── GettingStartedBlocksEn.vue
│ │ │ ├── GettingStartedBlocksZhCn.vue
│ │ │ ├── TitleBlockContainer.vue
│ │ │ └── TitleBlockContainerGroup.vue
│ │ ├── index.mts
│ │ └── style.css
│ ├── eslint.config.js
│ ├── package.json
│ ├── pages/
│ │ ├── en/
│ │ │ ├── acknowledgements.md
│ │ │ ├── guide/
│ │ │ │ ├── getting-started/
│ │ │ │ │ ├── cli.md
│ │ │ │ │ ├── crd.md
│ │ │ │ │ └── index.md
│ │ │ │ ├── overview.md
│ │ │ │ └── supported-models.md
│ │ │ ├── index.md
│ │ │ ├── references/
│ │ │ │ ├── architectural-design.md
│ │ │ │ ├── cli/
│ │ │ │ │ ├── commands/
│ │ │ │ │ │ ├── deploy.md
│ │ │ │ │ │ ├── expose.md
│ │ │ │ │ │ └── undeploy.md
│ │ │ │ │ └── index.md
│ │ │ │ └── crd/
│ │ │ │ ├── index.md
│ │ │ │ └── model.md
│ │ │ └── snippets/
│ │ │ ├── deploy-kubernetes-cluster-with-kind.md
│ │ │ └── install-ollama-operator.md
│ │ └── zh-CN/
│ │ ├── acknowledgements.md
│ │ ├── guide/
│ │ │ ├── getting-started/
│ │ │ │ ├── cli.md
│ │ │ │ ├── crd.md
│ │ │ │ └── index.md
│ │ │ ├── overview.md
│ │ │ └── supported-models.md
│ │ ├── index.md
│ │ ├── references/
│ │ │ ├── architectural-design.md
│ │ │ ├── cli/
│ │ │ │ ├── commands/
│ │ │ │ │ ├── deploy.md
│ │ │ │ │ ├── expose.md
│ │ │ │ │ └── undeploy.md
│ │ │ │ └── index.md
│ │ │ └── crd/
│ │ │ ├── index.md
│ │ │ └── model.md
│ │ └── snippets/
│ │ ├── deploy-kubernetes-cluster-with-kind.md
│ │ └── install-ollama-operator.md
│ ├── public/
│ │ ├── _redirects
│ │ ├── browserconfig.xml
│ │ ├── demo-full.cast
│ │ ├── demo.cast
│ │ └── site.webmanifest
│ ├── shim.d.ts
│ ├── tsconfig.json
│ ├── uno.config.ts
│ └── vite.config.mts
├── go.mod
├── go.sum
├── hack/
│ ├── boilerplate.go.txt
│ ├── kind-config.yaml
│ ├── ollama-model-llama2-kind-cluster.yaml
│ ├── ollama-model-llama2-nfs.yaml
│ ├── ollama-model-phi-kind-cluster.yaml
│ └── ollama-model-phi-nfs.yaml
├── internal/
│ ├── cli/
│ │ └── kollama/
│ │ ├── cmd.go
│ │ ├── cmd_deploy.go
│ │ ├── cmd_expose.go
│ │ ├── cmd_undeploy.go
│ │ ├── common.go
│ │ └── wait_until.go
│ └── controller/
│ └── model_controller.go
└── pkg/
├── model/
│ ├── image_store.go
│ ├── model.go
│ ├── model_test.go
│ ├── pod.go
│ ├── pod_test.go
│ └── recorder.go
└── operator/
└── reconcile.go
SYMBOL INDEX (156 symbols across 19 files)
FILE: api/ollama/v1/model_types.go
type ModelPersistentVolumeSpec (line 24) | type ModelPersistentVolumeSpec struct
type ModelSpec (line 35) | type ModelSpec struct
type ConditionType (line 107) | type ConditionType
constant ModelUnknown (line 114) | ModelUnknown ConditionType = "Unknown"
constant ModelAvailable (line 117) | ModelAvailable ConditionType = "Available"
constant ModelProgressing (line 122) | ModelProgressing ConditionType = "Progressing"
constant ModelReplicaFailure (line 125) | ModelReplicaFailure ConditionType = "ReplicaFailure"
type ModelStatusCondition (line 128) | type ModelStatusCondition struct
type ModelStatus (line 144) | type ModelStatus struct
type Model (line 176) | type Model struct
type ModelList (line 187) | type ModelList struct
function init (line 193) | func init() {
FILE: api/ollama/v1/zz_generated.deepcopy.go
method DeepCopyInto (line 29) | func (in *Model) DeepCopyInto(out *Model) {
method DeepCopy (line 38) | func (in *Model) DeepCopy() *Model {
method DeepCopyObject (line 48) | func (in *Model) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 56) | func (in *ModelList) DeepCopyInto(out *ModelList) {
method DeepCopy (line 70) | func (in *ModelList) DeepCopy() *ModelList {
method DeepCopyObject (line 80) | func (in *ModelList) DeepCopyObject() runtime.Object {
method DeepCopyInto (line 88) | func (in *ModelPersistentVolumeSpec) DeepCopyInto(out *ModelPersistentVo...
method DeepCopy (line 98) | func (in *ModelPersistentVolumeSpec) DeepCopy() *ModelPersistentVolumeSp...
method DeepCopyInto (line 108) | func (in *ModelSpec) DeepCopyInto(out *ModelSpec) {
method DeepCopy (line 163) | func (in *ModelSpec) DeepCopy() *ModelSpec {
method DeepCopyInto (line 173) | func (in *ModelStatus) DeepCopyInto(out *ModelStatus) {
method DeepCopy (line 185) | func (in *ModelStatus) DeepCopy() *ModelStatus {
method DeepCopyInto (line 195) | func (in *ModelStatusCondition) DeepCopyInto(out *ModelStatusCondition) {
method DeepCopy (line 202) | func (in *ModelStatusCondition) DeepCopy() *ModelStatusCondition {
FILE: cmd/kollama/main.go
function main (line 34) | func main() {
FILE: cmd/ollama-operator/main.go
function init (line 47) | func init() {
function main (line 54) | func main() {
FILE: docs/shim.d.ts
type PlayerCreateOptions (line 2) | interface PlayerCreateOptions {
type Player (line 24) | interface Player {
FILE: internal/cli/kollama/cmd.go
function NewCmd (line 35) | func NewCmd(streams genericiooptions.IOStreams) *cobra.Command {
FILE: internal/cli/kollama/cmd_deploy.go
constant deployExample (line 31) | deployExample = `
constant deployedNonExposedMessage (line 45) | deployedNonExposedMessage = `🎉 Successfully deployed %s.
constant deployedExposedMessage (line 61) | deployedExposedMessage = `🎉 Successfully deployed %s.
type CmdDeployOptions (line 83) | type CmdDeployOptions struct
method AddFlags (line 112) | func (o *CmdDeployOptions) AddFlags(flags *pflag.FlagSet) {
method runE (line 195) | func (o *CmdDeployOptions) runE(cmd *cobra.Command, args []string) err...
function NewCmdDeployOptions (line 105) | func NewCmdDeployOptions(streams genericiooptions.IOStreams) *CmdDeployO...
function NewCmdDeploy (line 161) | func NewCmdDeploy(streams genericiooptions.IOStreams) *cobra.Command {
FILE: internal/cli/kollama/cmd_expose.go
constant exposedMessage (line 27) | exposedMessage = `🎉 The model has been exposed through a service over %s.
type CmdExposeOptions (line 48) | type CmdExposeOptions struct
method AddFlags (line 71) | func (o *CmdExposeOptions) AddFlags(flags *pflag.FlagSet) {
method runE (line 121) | func (o *CmdExposeOptions) runE(cmd *cobra.Command, args []string) err...
function NewCmdExposeOptions (line 64) | func NewCmdExposeOptions(streams genericiooptions.IOStreams) *CmdExposeO...
function NewCmdExpose (line 87) | func NewCmdExpose(streams genericiooptions.IOStreams) *cobra.Command {
FILE: internal/cli/kollama/cmd_undeploy.go
constant unDeployExample (line 23) | unDeployExample = `
type CmdUndeployOptions (line 37) | type CmdUndeployOptions struct
method runE (line 87) | func (o *CmdUndeployOptions) runE(cmd *cobra.Command, args []string) e...
function NewCmdUndeployOptions (line 47) | func NewCmdUndeployOptions(streams genericiooptions.IOStreams) *CmdUndep...
function NewCmdUndeploy (line 54) | func NewCmdUndeploy(streams genericiooptions.IOStreams) *cobra.Command {
FILE: internal/cli/kollama/common.go
function isKubectlPlugin (line 34) | func isKubectlPlugin() (bool, error) {
function command (line 48) | func command() string {
function IsOllamaOperatorCRDSupported (line 57) | func IsOllamaOperatorCRDSupported(discoveryClient discovery.DiscoveryInt...
function FromUnstructured (line 79) | func FromUnstructured[T any](obj *unstructured.Unstructured) (*T, error) {
function Unstructured (line 90) | func Unstructured[T runtime.Object](obj T) (*unstructured.Unstructured, ...
function getOllama (line 105) | func getOllama(ctx context.Context, dynamicClient dynamic.Interface, nam...
function getNamespace (line 126) | func getNamespace(clientConfig clientcmd.ClientConfig, cmd *cobra.Comman...
function getImage (line 148) | func getImage(cmd *cobra.Command, args []string) (string, error) {
function createOllamaModel (line 163) | func createOllamaModel(
function exposeOllamaModel (line 215) | func exposeOllamaModel(
FILE: internal/cli/kollama/wait_until.go
constant isReadyString (line 20) | isReadyString = " is ready"
function waitUntilImageStoreReady (line 23) | func waitUntilImageStoreReady(ctx context.Context, kubeClient client.Cli...
function waitUntilImageStoreServiceReady (line 39) | func waitUntilImageStoreServiceReady(ctx context.Context, kubeClient cli...
function waitUntilOllamaModelDeploymentPullImageDone (line 55) | func waitUntilOllamaModelDeploymentPullImageDone(ctx context.Context, ku...
function waitUntilOllamaModelDeploymentReady (line 78) | func waitUntilOllamaModelDeploymentReady(ctx context.Context, kubeClient...
function waitUntilOllamaModelServiceReady (line 99) | func waitUntilOllamaModelServiceReady(ctx context.Context, kubeClient cl...
function waitUntilModelAvailable (line 115) | func waitUntilModelAvailable(kubeClient client.Client, namespace string,...
FILE: internal/controller/model_controller.go
type ModelReconciler (line 35) | type ModelReconciler struct
method Reconcile (line 60) | func (r *ModelReconciler) Reconcile(ctx context.Context, req ctrl.Requ...
method SetupWithManager (line 77) | func (r *ModelReconciler) SetupWithManager(mgr ctrl.Manager) error {
method reconcile (line 83) | func (r *ModelReconciler) reconcile(ctx context.Context, req ctrl.Requ...
method reconcilePVC (line 108) | func (r *ModelReconciler) reconcilePVC(ctx context.Context, ns string,...
method reconcileStatefulSet (line 121) | func (r *ModelReconciler) reconcileStatefulSet(ctx context.Context, ns...
method reconcileService (line 139) | func (r *ModelReconciler) reconcileService(ctx context.Context, ns str...
method reconcileDeployment (line 162) | func (r *ModelReconciler) reconcileDeployment(ctx context.Context, ns ...
method reconcileModelService (line 189) | func (r *ModelReconciler) reconcileModelService(ctx context.Context, n...
FILE: pkg/model/image_store.go
constant ImageStorePVCName (line 21) | ImageStorePVCName = "ollama-models-store-pvc"
constant ImageStoreStatefulSetName (line 22) | ImageStoreStatefulSetName = "ollama-models-store"
function getImageStorePVC (line 25) | func getImageStorePVC(ctx context.Context, client client.Client, namespa...
function EnsureImageStorePVCCreated (line 40) | func EnsureImageStorePVCCreated(
function GetImageStorePVByPVC (line 96) | func GetImageStorePVByPVC(ctx context.Context, c client.Client, pvc *cor...
function getImageStoreStatefulSet (line 111) | func getImageStoreStatefulSet(ctx context.Context, client client.Client,...
function EnsureImageStoreStatefulSetCreated (line 126) | func EnsureImageStoreStatefulSetCreated(
function IsImageStoreStatefulSetReady (line 195) | func IsImageStoreStatefulSetReady(
function getImageStoreService (line 222) | func getImageStoreService(ctx context.Context, client client.Client, nam...
function EnsureImageStoreServiceCreated (line 237) | func EnsureImageStoreServiceCreated(
function IsImageStoreServiceReady (line 296) | func IsImageStoreServiceReady(
FILE: pkg/model/model.go
function getServiceByLabels (line 22) | func getServiceByLabels(ctx context.Context, c client.Client, namespace ...
function ModelServiceName (line 40) | func ModelServiceName(name string) string {
function ModelAppName (line 44) | func ModelAppName(name string) string {
function ModelLabels (line 48) | func ModelLabels(name string) map[string]string {
function OllamaModelNameFromNameReference (line 57) | func OllamaModelNameFromNameReference(ref namepkg.Reference) string {
function ImageStoreLabels (line 66) | func ImageStoreLabels() map[string]string {
function ModelAnnotations (line 73) | func ModelAnnotations(name string, imageStore bool) map[string]string {
function getDeployment (line 77) | func getDeployment(ctx context.Context, c client.Client, namespace strin...
function EnsureDeploymentCreated (line 92) | func EnsureDeploymentCreated(
function MergePodTemplate (line 155) | func MergePodTemplate(
function AssignOrAppend (line 211) | func AssignOrAppend[T any](source []T, predicate func(item T) bool, modi...
function AppendIfNotFound (line 224) | func AppendIfNotFound[T any](source []T, predicate func(item T) bool, ne...
function IsDeploymentReady (line 233) | func IsDeploymentReady(
function UpdateDeployment (line 267) | func UpdateDeployment(
function NewServiceForModel (line 309) | func NewServiceForModel(namespace, name string, deployment *appsv1.Deplo...
function EnsureServiceCreated (line 338) | func EnsureServiceCreated(
function IsServiceReady (line 368) | func IsServiceReady(
function IsProgressing (line 398) | func IsProgressing(ctx context.Context, ollamaModelResource ollamav1.Mod...
function SetProgressing (line 404) | func SetProgressing(
function IsAvailable (line 433) | func IsAvailable(ctx context.Context, ollamaModelResource ollamav1.Model...
function SetAvailable (line 439) | func SetAvailable(
function ShouldSetReplicas (line 469) | func ShouldSetReplicas(
function SetReplicas (line 483) | func SetReplicas(
FILE: pkg/model/model_test.go
function TestModelNameFromImage (line 12) | func TestModelNameFromImage(t *testing.T) {
FILE: pkg/model/pod.go
constant OllamaBaseImage (line 17) | OllamaBaseImage = "ollama/ollama"
function FindOllamaServerContainer (line 20) | func FindOllamaServerContainer(container corev1.Container) bool {
function UniqEnvVar (line 24) | func UniqEnvVar(env []corev1.EnvVar) []corev1.EnvVar {
function AssignOllamaServerContainer (line 30) | func AssignOllamaServerContainer(readOnly bool, resources corev1.Resourc...
function NewOllamaServerContainer (line 111) | func NewOllamaServerContainer(readOnly bool, resources corev1.ResourceRe...
function FindOllamaPullerContainer (line 173) | func FindOllamaPullerContainer(container corev1.Container) bool {
function ioReaderOfJsonBody (line 177) | func ioReaderOfJsonBody(body map[string]any) (io.Reader, error) {
function ollamaPull (line 188) | func ollamaPull(image string) string {
function ollamaGenerate (line 197) | func ollamaGenerate(image string) string {
function AssignOllamaPullerContainer (line 206) | func AssignOllamaPullerContainer(name string, image string, parsedModelN...
function NewOllamaPullerContainer (line 231) | func NewOllamaPullerContainer(name string, image string, parsedModelName...
FILE: pkg/model/pod_test.go
function TestOllamaPull (line 9) | func TestOllamaPull(t *testing.T) {
function TestOllamaGenerate (line 14) | func TestOllamaGenerate(t *testing.T) {
FILE: pkg/model/recorder.go
type WrappedRecorder (line 11) | type WrappedRecorder struct
function NewWrappedRecorder (line 16) | func NewWrappedRecorder[T runtime.Object](recorder record.EventRecorder,...
method Event (line 23) | func (r *WrappedRecorder[T]) Event(eventType, reason, message string) {
method Eventf (line 28) | func (r *WrappedRecorder[T]) Eventf(eventType, reason, messageFmt string...
method AnnotatedEventf (line 33) | func (r *WrappedRecorder[T]) AnnotatedEventf(annotations map[string]stri...
type baseWrapperRecorderContextKey (line 37) | type baseWrapperRecorderContextKey
function NewWrappedRecorderContextKey (line 39) | func NewWrappedRecorderContextKey(key string) baseWrapperRecorderContext...
constant defaultBaseWrapperRecorderContextKey (line 44) | defaultBaseWrapperRecorderContextKey baseWrapperRecorderContextKey = "de...
function WithWrappedRecorder (line 47) | func WithWrappedRecorder[T runtime.Object](ctx context.Context, recorder...
function WrappedRecorderFromContext (line 55) | func WrappedRecorderFromContext[T runtime.Object](ctx context.Context, k...
type baseClientContextKey (line 66) | type baseClientContextKey
constant defaultBaseClientContextKey (line 69) | defaultBaseClientContextKey baseClientContextKey = "default"
function NewClientContextKey (line 72) | func NewClientContextKey(key string) baseClientContextKey {
function WithClient (line 76) | func WithClient(ctx context.Context, client client.Client, key ...baseCl...
function ClientFromContext (line 84) | func ClientFromContext(ctx context.Context, key ...baseClientContextKey)...
FILE: pkg/operator/reconcile.go
function ResultFromError (line 17) | func ResultFromError(err error) (*ctrl.Result, error) {
function HandleError (line 30) | func HandleError(ctx context.Context, result *ctrl.Result, err error) (c...
type SubReconciler (line 45) | type SubReconciler struct
type SubReconcilers (line 52) | type SubReconcilers
method Reconcile (line 54) | func (s SubReconcilers[T]) Reconcile(ctx context.Context, req ctrl.Reque...
function NewSubReconcilers (line 69) | func NewSubReconcilers[T runtime.Object](reconcilers ...SubReconciler[T]...
type ReconcileHandler (line 73) | type ReconcileHandler
function NewPVCReconciler (line 75) | func NewPVCReconciler[T runtime.Object](fn ReconcileHandler[T]) SubRecon...
function NewStatefulSetReconciler (line 84) | func NewStatefulSetReconciler[T runtime.Object](fn ReconcileHandler[T]) ...
function NewServiceReconciler (line 93) | func NewServiceReconciler[T runtime.Object](fn ReconcileHandler[T]) SubR...
function NewDeploymentReconciler (line 102) | func NewDeploymentReconciler[T runtime.Object](fn ReconcileHandler[T]) S...
function RequeueAfter (line 111) | func RequeueAfter(d time.Duration) error {
function RequeueAfterWithError (line 115) | func RequeueAfterWithError(d time.Duration, err error) error {
type RequeueError (line 119) | type RequeueError struct
method Error (line 124) | func (r *RequeueError) Error() string {
method Result (line 132) | func (r *RequeueError) Result() reconcile.Result {
Condensed preview — 124 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,076K chars).
[
{
"path": ".dockerignore",
"chars": 120,
"preview": "# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file\n# Ignore build and test binaries.\nbin/\n"
},
{
"path": ".github/FUNDING.yml",
"chars": 758,
"preview": "# These are supported funding model platforms\n\ngithub: [nekomeowww]\n# patreon: # Replace with a single Patreon username\n"
},
{
"path": ".github/renovate.json",
"chars": 415,
"preview": "{\n \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n \"automerge\": true,\n \"extends\": [\n \"con"
},
{
"path": ".github/workflows/ci.yaml",
"chars": 1175,
"preview": "name: CI\n\non:\n push:\n paths-ignore:\n - 'docs/pages/**'\n branches:\n - main\n pull_request:\n paths-ign"
},
{
"path": ".github/workflows/pr-docs-build.yaml",
"chars": 2313,
"preview": "name: Build PR Previewing Docs\n\non:\n pull_request:\n branches:\n - main\n paths:\n - 'docs/**'\n\njobs:\n bui"
},
{
"path": ".github/workflows/pr-docs-deployment.yaml",
"chars": 4459,
"preview": "name: Push PR Previewing Docs to Cloudflare Pages\n\non:\n workflow_run:\n workflows:\n - Build PR Previewing Docs\n "
},
{
"path": ".github/workflows/production-docs-deployment.yaml",
"chars": 1788,
"preview": "name: Build Docs to Cloudflare Pages\n\non:\n push:\n branches:\n - 'main'\n\njobs:\n build:\n name: Build\n runs-"
},
{
"path": ".github/workflows/release-build.yml",
"chars": 2700,
"preview": "name: Release Build\n\non:\n push:\n tags:\n - '**'\n workflow_dispatch:\n\njobs:\n goreleaser:\n name: kollama - Bu"
},
{
"path": ".github/workflows/unstable-build.yml",
"chars": 1538,
"preview": "name: Unstable Build\n\non:\n workflow_dispatch:\n\njobs:\n ghcr_build:\n name: Build for GitHub Container Registry\n pe"
},
{
"path": ".gitignore",
"chars": 706,
"preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\nbin/*\nDockerfile.cross\n\n# Built application files\n!d"
},
{
"path": ".golangci.yml",
"chars": 2090,
"preview": "version: \"2\"\nrun:\n allow-parallel-runners: true\nlinters:\n default: all\n disable:\n - containedctx\n - contextchec"
},
{
"path": ".goreleaser.yml",
"chars": 479,
"preview": "project_name: kollama\nrelease:\n github:\n owner: nekomeowww\n name: ollama-operator\nbuilds:\n - id: kollama\n goo"
},
{
"path": ".krew.yaml",
"chars": 1755,
"preview": "apiVersion: krew.googlecontainertools.github.com/v1alpha2\nkind: Plugin\nmetadata:\n name: kollama\nspec:\n version: {{ .Ta"
},
{
"path": ".tool-versions",
"chars": 35,
"preview": "golang 1.26.1\ngolangci-lint 2.11.3\n"
},
{
"path": ".vscode/settings.json",
"chars": 560,
"preview": "{\n \"editor.formatOnSave\": false,\n \"editor.codeActionsOnSave\": {\n \"source.fixAll.eslint\": \"explicit\",\n "
},
{
"path": "CONTRIBUTING.md",
"chars": 4178,
"preview": "# Contributing to Ollama Operator\n\n### Prerequisites\n\n- `go` version `v1.24.0+`\n- `docker` version `17.03+`.\n- `kubectl`"
},
{
"path": "Dockerfile",
"chars": 1410,
"preview": "# Build the manager binary\nFROM golang:1.26 AS builder\n\nARG TARGETOS\nARG TARGETARCH\n\nWORKDIR /workspace\n\n# Copy the Go M"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 8693,
"preview": "# Image URL to use all building/pushing image targets\nIMG ?= ghcr.io/nekomeowww/ollama-operator:0.10.7\n# ENVTEST_K8S_VER"
},
{
"path": "PROJECT",
"chars": 544,
"preview": "# Code generated by tool. DO NOT EDIT.\n# This file is used to track the info used to scaffold your project\n# and allow t"
},
{
"path": "README.md",
"chars": 7206,
"preview": "<div align=\"center\">\n <img alt=\"ollama\" height=\"200px\" src=\"./docs/public/logo.png\">\n</div>\n\n# Ollama Operator\n\n[![Disc"
},
{
"path": "api/ollama/v1/groupversion_info.go",
"chars": 1201,
"preview": "/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
},
{
"path": "api/ollama/v1/model_types.go",
"chars": 10016,
"preview": "/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
},
{
"path": "api/ollama/v1/zz_generated.deepcopy.go",
"chars": 6051,
"preview": "//go:build !ignore_autogenerated\n\n/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyo"
},
{
"path": "cmd/kollama/main.go",
"chars": 1360,
"preview": "/*\nCopyright 2018 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "cmd/ollama-operator/main.go",
"chars": 5151,
"preview": "/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
},
{
"path": "config/crd/bases/ollama.ayaka.io_models.yaml",
"chars": 616651,
"preview": "---\napiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n annotations:\n controller-gen.kubeb"
},
{
"path": "config/crd/kustomization.yaml",
"chars": 969,
"preview": "# This kustomization.yaml is not intended to be run by itself,\n# since it depends on service name and namespace that are"
},
{
"path": "config/crd/kustomizeconfig.yaml",
"chars": 506,
"preview": "# This file is for teaching kustomize how to substitute name and namespace reference in CRD\nnameReference:\n- kind: Servi"
},
{
"path": "config/default/kustomization.yaml",
"chars": 4675,
"preview": "# Adds namespace to all resources.\nnamespace: ollama-operator-system\n\n# Value of this field is prepended to the\n# names "
},
{
"path": "config/default/manager_auth_proxy_patch.yaml",
"chars": 1093,
"preview": "# This patch inject a sidecar container which is a HTTP proxy for the\n# controller manager, it performs RBAC authorizati"
},
{
"path": "config/default/manager_config_patch.yaml",
"chars": 162,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: controller-manager\n namespace: system\nspec:\n template:\n spec"
},
{
"path": "config/manager/kustomization.yaml",
"chars": 181,
"preview": "resources:\n- manager.yaml\napiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nimages:\n- name: controller\n n"
},
{
"path": "config/manager/manager.yaml",
"chars": 3497,
"preview": "apiVersion: v1\nkind: Namespace\nmetadata:\n labels:\n control-plane: controller-manager\n app.kubernetes.io/name: nam"
},
{
"path": "config/prometheus/kustomization.yaml",
"chars": 26,
"preview": "resources:\n- monitor.yaml\n"
},
{
"path": "config/prometheus/monitor.yaml",
"chars": 782,
"preview": "# Prometheus Monitor Service (Metrics)\napiVersion: monitoring.coreos.com/v1\nkind: ServiceMonitor\nmetadata:\n labels:\n "
},
{
"path": "config/rbac/auth_proxy_client_clusterrole.yaml",
"chars": 437,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n labels:\n app.kubernetes.io/name: clusterrole\n "
},
{
"path": "config/rbac/auth_proxy_role.yaml",
"chars": 563,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n labels:\n app.kubernetes.io/name: clusterrole\n "
},
{
"path": "config/rbac/auth_proxy_role_binding.yaml",
"chars": 565,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n labels:\n app.kubernetes.io/name: cluste"
},
{
"path": "config/rbac/auth_proxy_service.yaml",
"chars": 579,
"preview": "apiVersion: v1\nkind: Service\nmetadata:\n labels:\n control-plane: controller-manager\n app.kubernetes.io/name: servi"
},
{
"path": "config/rbac/kustomization.yaml",
"chars": 693,
"preview": "resources:\n# All RBAC will be applied under this service account in\n# the deployment namespace. You may comment out this"
},
{
"path": "config/rbac/leader_election_role.yaml",
"chars": 751,
"preview": "# permissions to do leader election.\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n labels:\n app.kub"
},
{
"path": "config/rbac/leader_election_role_binding.yaml",
"chars": 563,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n labels:\n app.kubernetes.io/name: rolebinding\n "
},
{
"path": "config/rbac/model_editor_role.yaml",
"chars": 642,
"preview": "# permissions for end users to edit models.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n label"
},
{
"path": "config/rbac/model_viewer_role.yaml",
"chars": 599,
"preview": "# permissions for end users to view models.\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n label"
},
{
"path": "config/rbac/role.yaml",
"chars": 1065,
"preview": "---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n name: manager-role\nrules:\n- apiGroups:\n - \"\""
},
{
"path": "config/rbac/role_binding.yaml",
"chars": 560,
"preview": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n labels:\n app.kubernetes.io/name: cluste"
},
{
"path": "config/rbac/service_account.yaml",
"chars": 191,
"preview": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n labels:\n app.kubernetes.io/name: ollama-operator\n app.kubernetes.i"
},
{
"path": "config/samples/kustomization.yaml",
"chars": 120,
"preview": "## Append samples of your project ##\nresources:\n- ollama_v1_model.yaml\n#+kubebuilder:scaffold:manifestskustomizesamples\n"
},
{
"path": "config/samples/ollama_v1_model.yaml",
"chars": 191,
"preview": "apiVersion: ollama.ayaka.io/v1\nkind: Model\nmetadata:\n labels:\n app.kubernetes.io/name: ollama-operator\n app.kuber"
},
{
"path": "cspell.config.yaml",
"chars": 1721,
"preview": "version: \"0.2\"\nignorePaths: []\ndictionaryDefinitions: []\ndictionaries: []\nwords:\n - alices\n - AnnotatedEventf\n - antf"
},
{
"path": "docs/.editorconfig",
"chars": 147,
"preview": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_"
},
{
"path": "docs/.vitepress/config.mts",
"chars": 8359,
"preview": "import { defineConfig } from 'vitepress'\nimport { tabsMarkdownPlugin } from 'vitepress-plugin-tabs'\n\n// https://vitepres"
},
{
"path": "docs/.vitepress/theme/components/GettingStartedBlocksEn.vue",
"chars": 3854,
"preview": "<template>\n <TitleBlockContainerGroup>\n <TitleBlockContainer\n href=\"/pages/en/guide/getting-started/cli\"\n "
},
{
"path": "docs/.vitepress/theme/components/GettingStartedBlocksZhCn.vue",
"chars": 3733,
"preview": "<template>\n <TitleBlockContainerGroup>\n <TitleBlockContainer\n href=\"/pages/zh-CN/guide/getting-started/cli\"\n "
},
{
"path": "docs/.vitepress/theme/components/TitleBlockContainer.vue",
"chars": 690,
"preview": "<script setup lang=\"ts\">\nconst props = defineProps<{\n title?: string\n href?: string\n}>()\n</script>\n\n<template>\n <a\n "
},
{
"path": "docs/.vitepress/theme/components/TitleBlockContainerGroup.vue",
"chars": 92,
"preview": "<template>\n <div flex=\"~ row <md:col\" w-full my-4 gap-4>\n <slot />\n </div>\n</template>\n"
},
{
"path": "docs/.vitepress/theme/index.mts",
"chars": 2630,
"preview": "// https://vitepress.dev/guide/custom-theme\nimport { h } from 'vue'\nimport type { Theme } from 'vitepress'\nimport Defaul"
},
{
"path": "docs/.vitepress/theme/style.css",
"chars": 4277,
"preview": "/**\n * Customize default theme styling by overriding CSS variables:\n * https://github.com/vuejs/vitepress/blob/main/src/"
},
{
"path": "docs/eslint.config.js",
"chars": 134,
"preview": "import antfu from '@antfu/eslint-config'\n\nexport default antfu({\n ignores: [\n '**/*.md',\n '**/*.yaml',\n '**/*."
},
{
"path": "docs/package.json",
"chars": 1206,
"preview": "{\n \"name\": \"docs\",\n \"type\": \"module\",\n \"packageManager\": \"pnpm@10.32.1\",\n \"scripts\": {\n \"docs:dev\": \"vitepress de"
},
{
"path": "docs/pages/en/acknowledgements.md",
"chars": 338,
"preview": "# Acknowledgements\n\nGratefully thanks to the following projects and their authors, contributors:\n\n- [Ollama](https://git"
},
{
"path": "docs/pages/en/guide/getting-started/cli.md",
"chars": 965,
"preview": "# Deploy through `kollama` CLI\n\nWe have a CLI called `kollama` here to simplify the deployment process. It is a simple w"
},
{
"path": "docs/pages/en/guide/getting-started/crd.md",
"chars": 2489,
"preview": "# Deploy models through CRD\n\n## Deploy the model\n\n1. Create one [`Model` CRD](/pages/en/references/crd/model) to rule th"
},
{
"path": "docs/pages/en/guide/getting-started/index.md",
"chars": 620,
"preview": "# Getting Started\n\n## Install operator\n\n<!--@include: @/pages/en/snippets/deploy-kubernetes-cluster-with-kind.md-->\n\n<!-"
},
{
"path": "docs/pages/en/guide/overview.md",
"chars": 3512,
"preview": "# Overview\n\nWhile [Ollama](https://github.com/ollama/ollama) is a powerful tool for running large language models locall"
},
{
"path": "docs/pages/en/guide/supported-models.md",
"chars": 5220,
"preview": "# Supported models\n\nThe out of box supported models are listed below.\nYou can use them directly by specifying the model "
},
{
"path": "docs/pages/en/index.md",
"chars": 1754,
"preview": "---\nlayout: home\nsidebar: false\n\ntitle: Ollama Operator\n\nhero:\n name: Ollama Operator\n text: Large language models, sc"
},
{
"path": "docs/pages/en/references/architectural-design.md",
"chars": 1915,
"preview": "# Architectural Design\n\nThere are two major components that the Ollama Operator will create for:\n\n1. **Model Inferencing"
},
{
"path": "docs/pages/en/references/cli/commands/deploy.md",
"chars": 9779,
"preview": "# `kollama deploy`\n\n`kollama deploy` command is used to deploy a [`Model`](/pages/en/references/crd/model) to the Kubern"
},
{
"path": "docs/pages/en/references/cli/commands/expose.md",
"chars": 4090,
"preview": "# `kollama expose`\n\n`kolamma expose` is a command to expose a [`Model`](/pages/en/references/crd/model) as a service.\n\n["
},
{
"path": "docs/pages/en/references/cli/commands/undeploy.md",
"chars": 1443,
"preview": "# `kollama undeploy`\n\n::: info No need to worry about deleting past [`Model`](/pages/en/references/crd/model) deployment"
},
{
"path": "docs/pages/en/references/cli/index.md",
"chars": 220,
"preview": "# `kollama` CLI Reference\n\n- [`kollama deploy`](/pages/en/references/cli/commands/deploy)\n- [`kollama undeploy`](/pages/"
},
{
"path": "docs/pages/en/references/crd/index.md",
"chars": 61,
"preview": "# CRD Reference\n\n- [`Model`](/pages/en/references/crd/model)\n"
},
{
"path": "docs/pages/en/references/crd/model.md",
"chars": 1155,
"preview": "# `Model`\n\n`Model` is a custom resource definition (CRD) that represents a Ollama server instance in the cluster.\n\nWhen "
},
{
"path": "docs/pages/en/snippets/deploy-kubernetes-cluster-with-kind.md",
"chars": 1166,
"preview": "::: tip Don't have an existing Kubernetes cluster?\n\nRun the following commands to create a new Kubernetes cluster with `"
},
{
"path": "docs/pages/en/snippets/install-ollama-operator.md",
"chars": 356,
"preview": "1. Install operator.\n\n```shell\nkubectl apply \\\n --server-side=true \\\n -f https://raw.githubusercontent.com/nekomeowww/"
},
{
"path": "docs/pages/zh-CN/acknowledgements.md",
"chars": 213,
"preview": "# 致谢\n\n非常感谢以下项目的作者和贡献者:\n\n- [Ollama](https://github.com/ollama/ollama)\n- [llama.cpp](https://github.com/ggerganov/llama.cp"
},
{
"path": "docs/pages/zh-CN/guide/getting-started/cli.md",
"chars": 812,
"preview": "# 通过 `kollama` CLI 进行部署\n\n我们有一个名为 `kollama` 的 CLI 来简化部署过程。这是一种将 Ollama 模型部署到 Kubernetes 集群的简单方法。\n\n## 开始操作\n\n1. 通过 `go inst"
},
{
"path": "docs/pages/zh-CN/guide/getting-started/crd.md",
"chars": 2031,
"preview": "# 通过 CRD 部署\n\n## 部署模型\n\n1. 创建一个 [`Model`](/pages/zh-CN/references/crd/model) 类型的 CRD 资源\n\n::: tip 什么是 CRD?\n\nCRD 是 Kubernete"
},
{
"path": "docs/pages/zh-CN/guide/getting-started/index.md",
"chars": 395,
"preview": "# 快速上手\n\n## 安装 Ollama Operator\n\n<!--@include: @/pages/zh-CN/snippets/deploy-kubernetes-cluster-with-kind.md-->\n\n<!--@incl"
},
{
"path": "docs/pages/zh-CN/guide/overview.md",
"chars": 2265,
"preview": "# 概览\n\n即便 [Ollama](https://github.com/ollama/ollama) 已经是一个强大的用于在本地运行大型语言模型的工具,并且 CLI 的用户体验与使用 Docker CLI 相同,但可惜的是,目前还无法在 "
},
{
"path": "docs/pages/zh-CN/guide/supported-models.md",
"chars": 4545,
"preview": "# 支持的模型\n\n支持的开箱即用的模型列表如下。\n您可以通过在 `Model` CRD 中指定模型镜像字段 `image` 来直接使用它们。\n\n> [!TIP] 不止这些\n> 借助由 Ollama 支持的 [`Modelfile`](htt"
},
{
"path": "docs/pages/zh-CN/index.md",
"chars": 1325,
"preview": "---\nlayout: home\nsidebar: false\n\ntitle: Ollama Operator\n\nhero:\n name: Ollama Operator\n text: 大语言模型,伸缩自如,轻松部署\n tagline"
},
{
"path": "docs/pages/zh-CN/references/architectural-design.md",
"chars": 1086,
"preview": "# 架构设计\n\nOllama Operator 会根据 CRD 的定义,创建两个主要组件:\n\n1. **模型推理服务**:模型推断服务器是一个简单的 API 服务器,用于运行模型并为模型的 API 提供服务。它在 Kubernetes 集群"
},
{
"path": "docs/pages/zh-CN/references/cli/commands/deploy.md",
"chars": 8694,
"preview": "# `kollama deploy`\n\n`kollama deploy` 命令用于将 [`Model`](/pages/zh-CN/references/crd/model) 部署到 Kubernetes 集群。它是通过操作 CRD 资源与"
},
{
"path": "docs/pages/zh-CN/references/cli/commands/expose.md",
"chars": 2904,
"preview": "# `kollama expose`\n\n`kollama expose` 用于暴露 [`Model`](/pages/zh-CN/references/crd/model) 服务。\n\n[[toc]]\n\n## 用例\n\n### 暴露 [`Mod"
},
{
"path": "docs/pages/zh-CN/references/cli/commands/undeploy.md",
"chars": 949,
"preview": "# `kollama undeploy`\n\n::: info 无需担心删除过去的 [`Model`](/pages/zh-CN/references/crd/model) 部署后会需要重新下载模型镜像哦!\n\nOllama Operator "
},
{
"path": "docs/pages/zh-CN/references/cli/index.md",
"chars": 222,
"preview": "# `kollama` CLI 参考\n\n- [`kollama deploy`](/pages/zh-CN/references/cli/commands/deploy)\n- [`kollama undeploy`](/pages/zh-C"
},
{
"path": "docs/pages/zh-CN/references/crd/index.md",
"chars": 57,
"preview": "# CRD 参考\n\n- [`Model`](/pages/zh-CN/references/crd/model)\n"
},
{
"path": "docs/pages/zh-CN/references/crd/model.md",
"chars": 987,
"preview": "# `Model` 模型资源\n\n`Model` 是一个自定义资源定义(CRD),代表集群中的一个 Ollama 推理服务实例。\n\n创建时,`Model` 的创建会触发对 [`Deployment`](https://kubernetes.i"
},
{
"path": "docs/pages/zh-CN/snippets/deploy-kubernetes-cluster-with-kind.md",
"chars": 1128,
"preview": "::: tip 没有现成的 Kubernetes 集群吗?\n\n运行以下命令以在您的本地机器上安装 Docker 和 kind 并创建一个 Kubernetes 集群:\n\n::: code-group\n\n```shell [macOS]\nbr"
},
{
"path": "docs/pages/zh-CN/snippets/install-ollama-operator.md",
"chars": 332,
"preview": "1. 安装 Operator.\n\n```shell\nkubectl apply \\\n --server-side=true \\\n -f https://raw.githubusercontent.com/nekomeowww/ollam"
},
{
"path": "docs/public/_redirects",
"chars": 22,
"preview": "/ /pages/en/ 301\n"
},
{
"path": "docs/public/browserconfig.xml",
"chars": 246,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n <msapplication>\n <tile>\n <square150x150logo"
},
{
"path": "docs/public/demo-full.cast",
"chars": 65973,
"preview": "{\"version\": 2, \"width\": 185, \"height\": 48, \"timestamp\": 1712909764, \"env\": {\"SHELL\": \"/bin/zsh\", \"TERM\": \"xterm-256color"
},
{
"path": "docs/public/demo.cast",
"chars": 37251,
"preview": "{\"version\": 2, \"width\": 110, \"height\": 32, \"timestamp\": 1712912885, \"env\": {\"SHELL\": \"/bin/zsh\", \"TERM\": \"xterm-256color"
},
{
"path": "docs/public/site.webmanifest",
"chars": 426,
"preview": "{\n \"name\": \"\",\n \"short_name\": \"\",\n \"icons\": [\n {\n \"src\": \"/android-chrome-192x192.png\",\n "
},
{
"path": "docs/shim.d.ts",
"chars": 892,
"preview": "declare module 'asciinema-player' {\n interface PlayerCreateOptions {\n cols?: number;\n rows?: number;\n autoPlay"
},
{
"path": "docs/tsconfig.json",
"chars": 671,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"ESNext\",\n \"jsx\": \"preserve\",\n \"lib\": [\n \"DOM\",\n \"ESNext\"\n ],\n"
},
{
"path": "docs/uno.config.ts",
"chars": 455,
"preview": "import { defineConfig, presetAttributify, presetIcons, presetUno } from 'unocss'\n\nexport default defineConfig({\n shortc"
},
{
"path": "docs/vite.config.mts",
"chars": 977,
"preview": "import { join } from 'node:path'\nimport { defineConfig } from 'vite'\nimport UnoCSS from 'unocss/vite'\nimport Inspect fro"
},
{
"path": "go.mod",
"chars": 5054,
"preview": "module github.com/nekomeowww/ollama-operator\n\ngo 1.25.7\n\ntoolchain go1.26.1\n\nrequire (\n\tgithub.com/briandowns/spinner v1"
},
{
"path": "go.sum",
"chars": 29445,
"preview": "entgo.io/ent v0.14.5 h1:Rj2WOYJtCkWyFo6a+5wB3EfBRP0rnx1fMk6gGA0UUe4=\nentgo.io/ent v0.14.5/go.mod h1:zTzLmWtPvGpmSwtkaayM"
},
{
"path": "hack/boilerplate.go.txt",
"chars": 546,
"preview": "/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
},
{
"path": "hack/kind-config.yaml",
"chars": 375,
"preview": "kind: Cluster\napiVersion: kind.x-k8s.io/v1alpha4\nnodes:\n- role: control-plane\n- role: worker\n extraPortMappings:\n - co"
},
{
"path": "hack/ollama-model-llama2-kind-cluster.yaml",
"chars": 140,
"preview": "apiVersion: ollama.ayaka.io/v1\nkind: Model\nmetadata:\n name: llama2\nspec:\n image: llama2\n persistentVolume:\n access"
},
{
"path": "hack/ollama-model-llama2-nfs.yaml",
"chars": 118,
"preview": "apiVersion: ollama.ayaka.io/v1\nkind: Model\nmetadata:\n name: llama2\nspec:\n image: llama2\n storageClassName: nfs-csi\n"
},
{
"path": "hack/ollama-model-phi-kind-cluster.yaml",
"chars": 134,
"preview": "apiVersion: ollama.ayaka.io/v1\nkind: Model\nmetadata:\n name: phi\nspec:\n image: phi\n persistentVolume:\n accessMode: "
},
{
"path": "hack/ollama-model-phi-nfs.yaml",
"chars": 112,
"preview": "apiVersion: ollama.ayaka.io/v1\nkind: Model\nmetadata:\n name: phi\nspec:\n image: phi\n storageClassName: nfs-csi\n"
},
{
"path": "internal/cli/kollama/cmd.go",
"chars": 1336,
"preview": "/*\nCopyright 2018 The Kubernetes Authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not u"
},
{
"path": "internal/cli/kollama/cmd_deploy.go",
"chars": 9111,
"preview": "package kollama\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/briandowns/spinner\"\n\t\""
},
{
"path": "internal/cli/kollama/cmd_expose.go",
"chars": 4670,
"preview": "package kollama\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/samber/lo\"\n\t\"github.com/spf"
},
{
"path": "internal/cli/kollama/cmd_undeploy.go",
"chars": 2961,
"preview": "package kollama\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/samber/lo\"\n\t\"github.com/spf13/cobra\"\n\n\tmetav"
},
{
"path": "internal/cli/kollama/common.go",
"chars": 6386,
"preview": "package kollama\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcor"
},
{
"path": "internal/cli/kollama/wait_until.go",
"chars": 4886,
"preview": "package kollama\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gookit/color\"\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8"
},
{
"path": "internal/controller/model_controller.go",
"chars": 7156,
"preview": "/*\nCopyright 2024.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in "
},
{
"path": "pkg/model/image_store.go",
"chars": 8471,
"preview": "package model\n\nimport (\n\t\"context\"\n\n\t\"github.com/samber/lo\"\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\t\""
},
{
"path": "pkg/model/model.go",
"chars": 13006,
"preview": "package model\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\n\tnamepkg \"github.com/google/go-containerregistry/pkg/name\"\n\t\"github"
},
{
"path": "pkg/model/model_test.go",
"chars": 1397,
"preview": "package model\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\t\"github.com/str"
},
{
"path": "pkg/model/pod.go",
"chars": 7480,
"preview": "package model\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/samber/lo\"\n\tcorev1 \"k8s.io/"
},
{
"path": "pkg/model/pod_test.go",
"chars": 556,
"preview": "package model\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestOllamaPull(t *testing.T) {\n\tcomman"
},
{
"path": "pkg/model/recorder.go",
"chars": 2639,
"preview": "package model\n\nimport (\n\t\"context\"\n\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/client-go/tools/record\"\n\t\"sigs.k8s.io/co"
},
{
"path": "pkg/operator/reconcile.go",
"chars": 3022,
"preview": "package operator\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\tctrl \"sigs.k8s.io/co"
}
]
About this extraction
This page contains the full source code of the nekomeowww/ollama-operator GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 124 files (996.0 KB), approximately 230.0k tokens, and a symbol index with 156 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.