쿠버네티스 문서에서 이 섹션은 개별의 태스크를 수행하는 방법을 보여준다. 한 태스크 페이지는 일반적으로 여러 단계로 이루어진 짧은 시퀀스를 제공함으로써, 하나의 일을 수행하는 방법을 보여준다.
만약 태스크 페이지를 작성하고 싶다면, 문서 풀 리퀘스트(Pull Request) 생성하기를 참조한다.
이 섹션의 다중 페이지 출력 화면임. 여기를 클릭하여 프린트.
쿠버네티스 문서에서 이 섹션은 개별의 태스크를 수행하는 방법을 보여준다. 한 태스크 페이지는 일반적으로 여러 단계로 이루어진 짧은 시퀀스를 제공함으로써, 하나의 일을 수행하는 방법을 보여준다.
만약 태스크 페이지를 작성하고 싶다면, 문서 풀 리퀘스트(Pull Request) 생성하기를 참조한다.
쿠버네티스 커맨드 라인 도구인 kubectl
을 사용하면
쿠버네티스 클러스터에 대해 명령을 실행할 수 있다.
kubectl
을 사용하여 애플리케이션을 배포하고, 클러스터 리소스를 검사 및 관리하고,
로그를 볼 수 있다. kubectl 전체 명령어를 포함한 추가 정보는
kubectl
레퍼런스 문서에서 확인할 수 있다.
kubectl
은 다양한 리눅스 플랫폼, macOS, 그리고 윈도우에 설치할 수 있다.
각각에 대한 설치 가이드는 다음과 같다.
kind를 사용하면 로컬 컴퓨터에서 쿠버네티스를 실행할 수 있다. 이 도구를 사용하려면 도커를 설치하고 구성해야 한다.
kind 퀵 스타트 페이지는 kind를 시작하고 실행하기 위해 수행해야 하는 작업을 보여준다.
kind
와 마찬가지로, minikube
는 쿠버네티스를 로컬에서 실행할 수 있는
도구이다. minikube
는 개인용 컴퓨터(윈도우, macOS 및 리눅스 PC 포함)에서
단일 노드 쿠버네티스 클러스터를 실행하여 쿠버네티스를 사용해보거나 일상적인 개발 작업을
수행할 수 있다.
도구 설치에 중점을 두고 있다면 공식 사이트에서의 시작하기! 가이드를 따라 해볼 수 있다.
minikube
가 작동하면, 이를 사용하여
샘플 애플리케이션을 실행해볼 수 있다.
kubeadm 도구를 사용하여 쿠버네티스 클러스터를 만들고 관리할 수 있다. 사용자 친화적인 방식으로 최소한의 실행 가능하고 안전한 클러스터를 설정하고 실행하는 데 필요한 작업을 수행한다.
kubeadm 설치 페이지는 kubeadm 설치하는 방법을 보여준다. 설치가 끝나면, 클러스터 생성이 가능하다.
클러스터의 마이너(minor) 버전 차이 내에 있는 kubectl 버전을 사용해야 한다. 예를 들어, v1.24 클라이언트는 v1.23, v1.24, v1.25의 컨트롤 플레인과 연동될 수 있다. 호환되는 최신 버전의 kubectl을 사용하면 예기치 않은 문제를 피할 수 있다.
다음과 같은 방법으로 macOS에 kubectl을 설치할 수 있다.
최신 릴리스를 다운로드한다.
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl"
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/arm64/kubectl"
특정 버전을 다운로드하려면, $(curl -L -s https://dl.k8s.io/release/stable.txt)
명령 부분을 특정 버전으로 바꾼다.
예를 들어, Intel macOS에 버전 v1.24.0을 다운로드하려면, 다음을 입력한다.
curl -LO "https://dl.k8s.io/release/v1.24.0/bin/darwin/amd64/kubectl"
Apple Silicon의 macOS라면, 다음을 입력한다.
curl -LO "https://dl.k8s.io/release/v1.24.0/bin/darwin/arm64/kubectl"
바이너리를 검증한다. (선택 사항)
kubectl 체크섬 파일을 다운로드한다.
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl.sha256"
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/arm64/kubectl.sha256"
kubectl 바이너리를 체크섬 파일을 통해 검증한다.
echo "$(<kubectl.sha256) kubectl" | shasum -a 256 --check
검증이 성공한다면, 출력은 다음과 같다.
kubectl: OK
검증이 실패한다면, shasum
이 0이 아닌 상태로 종료되며 다음과 유사한 결과를 출력한다.
kubectl: FAILED
shasum: WARNING: 1 computed checksum did NOT match
kubectl 바이너리를 실행 가능하게 한다.
chmod +x ./kubectl
kubectl 바이너리를 시스템 PATH
의 파일 위치로 옮긴다.
sudo mv ./kubectl /usr/local/bin/kubectl
sudo chown root: /usr/local/bin/kubectl
PATH
환경 변수 안에 /usr/local/bin
이 있는지 확인한다.설치한 버전이 최신 버전인지 확인한다.
kubectl version --client
macOS에서 Homebrew 패키지 관리자를 사용하는 경우, Homebrew로 kubectl을 설치할 수 있다.
설치 명령을 실행한다.
brew install kubectl
또는
brew install kubernetes-cli
설치한 버전이 최신 버전인지 확인한다.
kubectl version --client
macOS에서 Macports 패키지 관리자를 사용하는 경우, Macports로 kubectl을 설치할 수 있다.
설치 명령을 실행한다.
sudo port selfupdate
sudo port install kubectl
설치한 버전이 최신 버전인지 확인한다.
kubectl version --client
kubectl이 쿠버네티스 클러스터를 찾아 접근하려면,
kube-up.sh를
사용하여 클러스터를 생성하거나 Minikube 클러스터를 성공적으로 배포할 때 자동으로 생성되는
kubeconfig 파일이
필요하다.
기본적으로, kubectl 구성은 ~/.kube/config
에 있다.
클러스터 상태를 가져와서 kubectl이 올바르게 구성되어 있는지 확인한다.
kubectl cluster-info
URL 응답이 표시되면, kubectl이 클러스터에 접근하도록 올바르게 구성된 것이다.
다음과 비슷한 메시지가 표시되면, kubectl이 올바르게 구성되지 않았거나 쿠버네티스 클러스터에 연결할 수 없다.
The connection to the server <server-name:port> was refused - did you specify the right host or port?
예를 들어, 랩톱에서 로컬로 쿠버네티스 클러스터를 실행하려면, Minikube와 같은 도구를 먼저 설치한 다음 위에서 언급한 명령을 다시 실행해야 한다.
kubectl cluster-info가 URL 응답을 반환하지만 클러스터에 접근할 수 없는 경우, 올바르게 구성되었는지 확인하려면 다음을 사용한다.
kubectl cluster-info dump
kubectl은 Bash, Zsh, Fish, 및 PowerShell에 대한 자동 완성 지원을 제공하므로 입력을 위한 타이핑을 많이 절약할 수 있다.
다음은 Bash, Fish, 및 Zsh에 대한 자동 완성을 설정하는 절차이다.
Bash의 kubectl 자동 완성 스크립트는 kubectl completion bash
로 생성할 수 있다. 이 스크립트를 셸에 소싱하면 kubectl 자동 완성이 가능하다.
그러나 kubectl 자동 완성 스크립트는 미리 bash-completion을 설치해야 동작한다.
여기의 지침에서는 Bash 4.1 이상을 사용한다고 가정한다. 다음을 실행하여 Bash 버전을 확인할 수 있다.
echo $BASH_VERSION
너무 오래된 버전인 경우, Homebrew를 사용하여 설치/업그레이드할 수 있다.
brew install bash
셸을 다시 로드하고 원하는 버전을 사용 중인지 확인한다.
echo $BASH_VERSION $SHELL
Homebrew는 보통 /usr/local/bin/bash
에 설치한다.
bash-completion v2가 이미 설치되어 있는지 type_init_completion
으로 확인할 수 있다. 그렇지 않은 경우, Homebrew로 설치할 수 있다.
brew install bash-completion@2
이 명령의 출력에 명시된 바와 같이, ~/.bash_profile
파일에 다음을 추가한다.
export BASH_COMPLETION_COMPAT_DIR="/usr/local/etc/bash_completion.d"
[[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"
셸을 다시 로드하고 bash-completion v2가 올바르게 설치되었는지 type _init_completion
으로 확인한다.
이제 kubectl 자동 완성 스크립트가 모든 셸 세션에서 제공되도록 해야 한다. 이를 수행하는 방법에는 여러 가지가 있다.
자동 완성 스크립트를 ~/.bash_profile
파일에서 소싱한다.
echo 'source <(kubectl completion bash)' >>~/.bash_profile
자동 완성 스크립트를 /usr/local/etc/bash_completion.d
디렉터리에 추가한다.
kubectl completion bash >/usr/local/etc/bash_completion.d/kubectl
kubectl에 대한 앨리어스가 있는 경우, 해당 앨리어스로 작업하기 위해 셸 자동 완성을 확장할 수 있다.
echo 'alias k=kubectl' >>~/.bash_profile
echo 'complete -F __start_kubectl k' >>~/.bash_profile
Homebrew로 kubectl을 설치한 경우(여기의 설명을 참고), kubectl 자동 완성 스크립트가 이미 /usr/local/etc/bash_completion.d/kubectl
에 있을 것이다. 이 경우, 아무 것도 할 필요가 없다.
BASH_COMPLETION_COMPAT_DIR
디렉터리의 모든 파일을 소싱하므로, 후자의 두 가지 방법이 적용된다.어떤 경우든, 셸을 다시 로드하면, kubectl 자동 완성 기능이 작동할 것이다.
Fish용 kubectl 자동 완성 스크립트는 kubectl completion fish
명령으로 생성할 수 있다. 셸에서 자동 완성 스크립트를 소싱하면 kubectl 자동 완성 기능이 활성화된다.
모든 셸 세션에서 사용하려면, ~/.config/fish/config.fish
파일에 다음을 추가한다.
kubectl completion fish | source
셸을 다시 로드하면, kubectl 자동 완성 기능이 작동할 것이다.
Zsh용 kubectl 자동 완성 스크립트는 kubectl completion zsh
명령으로 생성할 수 있다. 셸에서 자동 완성 스크립트를 소싱하면 kubectl 자동 완성 기능이 활성화된다.
모든 셸 세션에서 사용하려면, ~/.zshrc
파일에 다음을 추가한다.
source <(kubectl completion zsh)
kubectl에 대한 앨리어스가 있는 경우, 해당 앨리어스로 작업하도록 셸 자동 완성을 확장할 수 있다.
echo 'alias k=kubectl' >>~/.zshrc
echo 'compdef __start_kubectl k' >>~/.zshrc
셸을 다시 로드하면, kubectl 자동 완성 기능이 작동할 것이다.
complete:13: command not found: compdef
와 같은 오류가 발생하면, ~/.zshrc
파일의 시작 부분에 다음을 추가한다.
autoload -Uz compinit
compinit
kubectl convert
플러그인 설치이것은 쿠버네티스 커맨드 라인 도구인 kubectl
의 플러그인으로서, 특정 버전의 쿠버네티스 API로 작성된 매니페스트를 다른 버전으로
변환할 수 있도록 한다. 이것은 매니페스트를 최신 쿠버네티스 릴리스의 사용 중단되지 않은 API로 마이그레이션하는 데 특히 유용하다.
더 많은 정보는 다음의 사용 중단되지 않은 API로 마이그레이션을 참고한다.
다음 명령으로 최신 릴리스를 다운로드한다.
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl-convert"
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/arm64/kubectl-convert"
바이너리를 검증한다. (선택 사항)
kubectl-convert 체크섬(checksum) 파일을 다운로드한다.
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl-convert.sha256"
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/arm64/kubectl-convert.sha256"
kubectl-convert 바이너리를 체크섬 파일을 통해 검증한다.
echo "$(<kubectl-convert.sha256) kubectl-convert" | shasum -a 256 --check
검증이 성공한다면, 출력은 다음과 같다.
kubectl-convert: OK
검증이 실패한다면, shasum
이 0이 아닌 상태로 종료되며 다음과 유사한 결과를 출력한다.
kubectl-convert: FAILED
shasum: WARNING: 1 computed checksum did NOT match
kubectl-convert 바이너리를 실행 가능하게 한다.
chmod +x ./kubectl-convert
kubectl-convert 바이너리를 시스템 PATH
의 파일 위치로 옮긴다.
sudo mv ./kubectl-convert /usr/local/bin/kubectl-convert
sudo chown root: /usr/local/bin/kubectl-convert
PATH
환경 변수 안에 /usr/local/bin
이 있는지 확인한다.플러그인이 정상적으로 설치되었는지 확인한다.
kubectl convert --help
에러가 출력되지 않는다면, 플러그인이 정상적으로 설치된 것이다.
클러스터의 마이너(minor) 버전 차이 내에 있는 kubectl 버전을 사용해야 한다. 예를 들어, v1.24 클라이언트는 v1.23, v1.24, v1.25의 컨트롤 플레인과 연동될 수 있다. 호환되는 최신 버전의 kubectl을 사용하면 예기치 않은 문제를 피할 수 있다.
다음과 같은 방법으로 리눅스에 kubectl을 설치할 수 있다.
다음 명령으로 최신 릴리스를 다운로드한다.
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
특정 버전을 다운로드하려면, $(curl -L -s https://dl.k8s.io/release/stable.txt)
명령 부분을 특정 버전으로 바꾼다.
예를 들어, 리눅스에서 버전 v1.24.0을 다운로드하려면, 다음을 입력한다.
curl -LO https://dl.k8s.io/release/v1.24.0/bin/linux/amd64/kubectl
바이너리를 검증한다. (선택 사항)
kubectl 체크섬(checksum) 파일을 다운로드한다.
curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256"
kubectl 바이너리를 체크섬 파일을 통해 검증한다.
echo "$(<kubectl.sha256) kubectl" | sha256sum --check
검증이 성공한다면, 출력은 다음과 같다.
kubectl: OK
검증이 실패한다면, shasum
이 0이 아닌 상태로 종료되며 다음과 유사한 결과를 출력한다.
kubectl: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
kubectl 설치
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
대상 시스템에 root 접근 권한을 가지고 있지 않더라도, ~/.local/bin
디렉터리에 kubectl을 설치할 수 있다.
chmod +x kubectl
mkdir -p ~/.local/bin/kubectl
mv ./kubectl ~/.local/bin/kubectl
# 그리고 ~/.local/bin 을 $PATH의 앞부분 또는 뒷부분에 추가
설치한 버전이 최신인지 확인한다.
kubectl version --client
apt
패키지 색인을 업데이트하고 쿠버네티스 apt
리포지터리를 사용하는 데 필요한 패키지들을 설치한다.
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
구글 클라우드 공개 사이닝 키를 다운로드한다.
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
쿠버네티스 apt
리포지터리를 추가한다.
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
새 리포지터리의 apt
패키지 색인을 업데이트하고 kubectl을 설치한다.
sudo apt-get update
sudo apt-get install -y kubectl
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
sudo yum install -y kubectl
kubectl이 쿠버네티스 클러스터를 찾아 접근하려면,
kube-up.sh를
사용하여 클러스터를 생성하거나 Minikube 클러스터를 성공적으로 배포할 때 자동으로 생성되는
kubeconfig 파일이
필요하다.
기본적으로, kubectl 구성은 ~/.kube/config
에 있다.
클러스터 상태를 가져와서 kubectl이 올바르게 구성되어 있는지 확인한다.
kubectl cluster-info
URL 응답이 표시되면, kubectl이 클러스터에 접근하도록 올바르게 구성된 것이다.
다음과 비슷한 메시지가 표시되면, kubectl이 올바르게 구성되지 않았거나 쿠버네티스 클러스터에 연결할 수 없다.
The connection to the server <server-name:port> was refused - did you specify the right host or port?
예를 들어, 랩톱에서 로컬로 쿠버네티스 클러스터를 실행하려면, Minikube와 같은 도구를 먼저 설치한 다음 위에서 언급한 명령을 다시 실행해야 한다.
kubectl cluster-info가 URL 응답을 반환하지만 클러스터에 접근할 수 없는 경우, 올바르게 구성되었는지 확인하려면 다음을 사용한다.
kubectl cluster-info dump
kubectl은 Bash, Zsh, Fish, 및 PowerShell에 대한 자동 완성 지원을 제공하므로 입력을 위한 타이핑을 많이 절약할 수 있다.
다음은 Bash, Fish, 및 Zsh에 대한 자동 완성을 설정하는 절차이다.
Bash의 kubectl 자동 완성 스크립트는 kubectl completion bash
명령으로 생성할 수 있다. 셸에서 자동 완성 스크립트를 소싱(sourcing)하면 kubectl 자동 완성 기능이 활성화된다.
그러나, 자동 완성 스크립트는 bash-completion에 의존하고 있으며, 이 소프트웨어를 먼저 설치해야 한다(type _init_completion
을 실행하여 bash-completion이 이미 설치되어 있는지 확인할 수 있음).
bash-completion은 많은 패키지 관리자에 의해 제공된다(여기 참고). apt-get install bash-completion
또는 yum install bash-completion
등으로 설치할 수 있다.
위의 명령은 bash-completion의 기본 스크립트인 /usr/share/bash-completion/bash_completion
을 생성한다. 패키지 관리자에 따라, ~/.bashrc
파일에서 이 파일을 수동으로 소스(source)해야 한다.
확인하려면, 셸을 다시 로드하고 type _init_completion
을 실행한다. 명령이 성공하면, 이미 설정된 상태이고, 그렇지 않으면 ~/.bashrc
파일에 다음을 추가한다.
source /usr/share/bash-completion/bash_completion
셸을 다시 로드하고 type _init_completion
을 입력하여 bash-completion이 올바르게 설치되었는지 확인한다.
이제 kubectl 자동 완성 스크립트가 모든 셸 세션에서 제공되도록 해야 한다. 이를 수행할 수 있는 두 가지 방법이 있다.
echo 'source <(kubectl completion bash)' >>~/.bashrc
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null
kubectl에 대한 앨리어스(alias)가 있는 경우, 해당 앨리어스로 작업하도록 셸 자동 완성을 확장할 수 있다.
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -F __start_kubectl k' >>~/.bashrc
/etc/bash_completion.d
에 있는 모든 자동 완성 스크립트를 소싱한다.두 방법 모두 동일하다. 셸을 다시 로드하면, kubectl 자동 완성 기능이 작동할 것이다.
Fish용 kubectl 자동 완성 스크립트는 kubectl completion fish
명령으로 생성할 수 있다. 셸에서 자동 완성 스크립트를 소싱하면 kubectl 자동 완성 기능이 활성화된다.
모든 셸 세션에서 사용하려면, ~/.config/fish/config.fish
파일에 다음을 추가한다.
kubectl completion fish | source
셸을 다시 로드하면, kubectl 자동 완성 기능이 작동할 것이다.
Zsh용 kubectl 자동 완성 스크립트는 kubectl completion zsh
명령으로 생성할 수 있다. 셸에서 자동 완성 스크립트를 소싱하면 kubectl 자동 완성 기능이 활성화된다.
모든 셸 세션에서 사용하려면, ~/.zshrc
파일에 다음을 추가한다.
source <(kubectl completion zsh)
kubectl에 대한 앨리어스가 있는 경우, 해당 앨리어스로 작업하도록 셸 자동 완성을 확장할 수 있다.
echo 'alias k=kubectl' >>~/.zshrc
echo 'compdef __start_kubectl k' >>~/.zshrc
셸을 다시 로드하면, kubectl 자동 완성 기능이 작동할 것이다.
complete:13: command not found: compdef
와 같은 오류가 발생하면, ~/.zshrc
파일의 시작 부분에 다음을 추가한다.
autoload -Uz compinit
compinit
kubectl convert
플러그인 설치이것은 쿠버네티스 커맨드 라인 도구인 kubectl
의 플러그인으로서, 특정 버전의 쿠버네티스 API로 작성된 매니페스트를 다른 버전으로
변환할 수 있도록 한다. 이것은 매니페스트를 최신 쿠버네티스 릴리스의 사용 중단되지 않은 API로 마이그레이션하는 데 특히 유용하다.
더 많은 정보는 다음의 사용 중단되지 않은 API로 마이그레이션을 참고한다.
다음 명령으로 최신 릴리스를 다운로드한다.
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl-convert"
바이너리를 검증한다. (선택 사항)
kubectl-convert 체크섬(checksum) 파일을 다운로드한다.
curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl-convert.sha256"
kubectl-convert 바이너리를 체크섬 파일을 통해 검증한다.
echo "$(<kubectl-convert.sha256) kubectl-convert" | sha256sum --check
검증이 성공한다면, 출력은 다음과 같다.
kubectl-convert: OK
검증이 실패한다면, sha256
이 0이 아닌 상태로 종료되며 다음과 유사한 결과를 출력한다.
kubectl-convert: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
kubectl-convert 설치
sudo install -o root -g root -m 0755 kubectl-convert /usr/local/bin/kubectl-convert
플러그인이 정상적으로 설치되었는지 확인한다.
kubectl convert --help
에러가 출력되지 않는다면, 플러그인이 정상적으로 설치된 것이다.
클러스터의 마이너(minor) 버전 차이 내에 있는 kubectl 버전을 사용해야 한다. 예를 들어, v1.24 클라이언트는 v1.23, v1.24, v1.25의 컨트롤 플레인과 연동될 수 있다. 호환되는 최신 버전의 kubectl을 사용하면 예기치 않은 문제를 피할 수 있다.
다음과 같은 방법으로 윈도우에 kubectl을 설치할 수 있다.
최신 릴리스 v1.24.0를 다운로드한다.
또는 curl
을 설치한 경우, 다음 명령을 사용한다.
curl -LO "https://dl.k8s.io/release/v1.24.0/bin/windows/amd64/kubectl.exe"
바이너리를 검증한다. (선택 사항)
kubectl 체크섬 파일을 다운로드한다.
curl -LO "https://dl.k8s.io/v1.24.0/bin/windows/amd64/kubectl.exe.sha256"
kubectl 바이너리를 체크섬 파일을 통해 검증한다.
커맨드 프롬프트를 사용하는 경우, CertUtil
의 출력과 다운로드한 체크섬 파일을 수동으로 비교한다.
CertUtil -hashfile kubectl.exe SHA256
type kubectl.exe.sha256
PowerShell을 사용하는 경우, -eq
연산자를 통해 True
또는 False
결과가 출력되는 자동 검증을 수행한다.
$($(CertUtil -hashfile .\kubectl.exe SHA256)[1] -replace " ", "") -eq $(type .\kubectl.exe.sha256)
kubectl 바이너리가 있는 폴더를 PATH
환경 변수의 앞부분 또는 뒷부분에 추가
kubectl
의 버전이 다운로드한 버전과 같은지 확인한다.
kubectl version --client
kubectl
을 PATH
에 추가한다.
도커 데스크톱을 이전에 설치한 경우, 도커 데스크톱 설치 프로그램에서 추가한 PATH
항목 앞에 PATH
항목을 배치하거나 도커 데스크톱의 kubectl
을 제거해야 할 수도 있다.윈도우에 kubectl을 설치하기 위해서 Chocolatey 패키지 관리자나 Scoop 커맨드 라인 설치 프로그램을 사용할 수 있다.
choco install kubernetes-cli
scoop install kubectl
설치한 버전이 최신 버전인지 확인한다.
kubectl version --client
홈 디렉터리로 이동한다.
# cmd.exe를 사용한다면, 다음을 실행한다. cd %USERPROFILE%
cd ~
.kube
디렉터리를 생성한다.
mkdir .kube
금방 생성한 .kube
디렉터리로 이동한다.
cd .kube
원격 쿠버네티스 클러스터를 사용하도록 kubectl을 구성한다.
New-Item config -type file
kubectl이 쿠버네티스 클러스터를 찾아 접근하려면,
kube-up.sh를
사용하여 클러스터를 생성하거나 Minikube 클러스터를 성공적으로 배포할 때 자동으로 생성되는
kubeconfig 파일이
필요하다.
기본적으로, kubectl 구성은 ~/.kube/config
에 있다.
클러스터 상태를 가져와서 kubectl이 올바르게 구성되어 있는지 확인한다.
kubectl cluster-info
URL 응답이 표시되면, kubectl이 클러스터에 접근하도록 올바르게 구성된 것이다.
다음과 비슷한 메시지가 표시되면, kubectl이 올바르게 구성되지 않았거나 쿠버네티스 클러스터에 연결할 수 없다.
The connection to the server <server-name:port> was refused - did you specify the right host or port?
예를 들어, 랩톱에서 로컬로 쿠버네티스 클러스터를 실행하려면, Minikube와 같은 도구를 먼저 설치한 다음 위에서 언급한 명령을 다시 실행해야 한다.
kubectl cluster-info가 URL 응답을 반환하지만 클러스터에 접근할 수 없는 경우, 올바르게 구성되었는지 확인하려면 다음을 사용한다.
kubectl cluster-info dump
kubectl은 Bash, Zsh, Fish, 및 PowerShell에 대한 자동 완성 지원을 제공하므로 입력을 위한 타이핑을 많이 절약할 수 있다.
다음은 PowerShell에 대한 자동 완성을 설정하는 절차이다.
PowerShell용 kubectl 자동 완성 스크립트는 kubectl completion powershell
명령으로 생성할 수 있다.
모든 셸 세션에서 사용하려면, $PROFILE
파일에 다음을 추가한다.
kubectl completion powershell | Out-String | Invoke-Expression
이 명령은 PowerShell을 실행할 때마다 자동 완성 스크립트를 재생성한다. 아니면, 생성된 스크립트를 $PROFILE
파일에 직접 추가할 수도 있다.
생성된 스크립트를 $PROFILE
파일에 직접 추가하려면, PowerShell 프롬프트에서 다음 명령줄을 실행한다.
kubectl completion powershell >> $PROFILE
셸을 다시 불러오면, kubectl 자동 완성이 동작할 것이다.
kubectl convert
플러그인 설치이것은 쿠버네티스 커맨드 라인 도구인 kubectl
의 플러그인으로서, 특정 버전의 쿠버네티스 API로 작성된 매니페스트를 다른 버전으로
변환할 수 있도록 한다. 이것은 매니페스트를 최신 쿠버네티스 릴리스의 사용 중단되지 않은 API로 마이그레이션하는 데 특히 유용하다.
더 많은 정보는 다음의 사용 중단되지 않은 API로 마이그레이션을 참고한다.
다음 명령으로 최신 릴리스를 다운로드한다.
curl -LO "https://dl.k8s.io/release/v1.24.0/bin/windows/amd64/kubectl-convert.exe"
바이너리를 검증한다. (선택 사항)
kubectl-convert 체크섬(checksum) 파일을 다운로드한다.
curl -LO "https://dl.k8s.io/v1.24.0/bin/windows/amd64/kubectl-convert.exe.sha256"
kubectl-convert 바이너리를 체크섬 파일을 통해 검증한다.
커맨드 프롬프트를 사용하는 경우, CertUtil
의 출력과 다운로드한 체크섬 파일을 수동으로 비교한다.
CertUtil -hashfile kubectl-convert.exe SHA256
type kubectl-convert.exe.sha256
PowerShell을 사용하는 경우, -eq
연산자를 통해 True
또는 False
결과가 출력되는 자동 검증을 수행한다.
$($(CertUtil -hashfile .\kubectl-convert.exe SHA256)[1] -replace " ", "") -eq $(type .\kubectl-convert.exe.sha256)
kubectl 바이너리가 있는 폴더를 PATH
환경 변수의 앞부분 또는 뒷부분에 추가
플러그인이 정상적으로 설치되었는지 확인한다.
kubectl convert --help
에러가 출력되지 않는다면, 플러그인이 정상적으로 설치된 것이다.
Fish용 kubectl 자동 완성 스크립트는 kubectl completion fish
명령으로 생성할 수 있다. 셸에서 자동 완성 스크립트를 소싱하면 kubectl 자동 완성 기능이 활성화된다.
모든 셸 세션에서 사용하려면, ~/.config/fish/config.fish
파일에 다음을 추가한다.
kubectl completion fish | source
셸을 다시 로드하면, kubectl 자동 완성 기능이 작동할 것이다.
kubectl이 쿠버네티스 클러스터를 찾아 접근하려면,
kube-up.sh를
사용하여 클러스터를 생성하거나 Minikube 클러스터를 성공적으로 배포할 때 자동으로 생성되는
kubeconfig 파일이
필요하다.
기본적으로, kubectl 구성은 ~/.kube/config
에 있다.
클러스터 상태를 가져와서 kubectl이 올바르게 구성되어 있는지 확인한다.
kubectl cluster-info
URL 응답이 표시되면, kubectl이 클러스터에 접근하도록 올바르게 구성된 것이다.
다음과 비슷한 메시지가 표시되면, kubectl이 올바르게 구성되지 않았거나 쿠버네티스 클러스터에 연결할 수 없다.
The connection to the server <server-name:port> was refused - did you specify the right host or port?
예를 들어, 랩톱에서 로컬로 쿠버네티스 클러스터를 실행하려면, Minikube와 같은 도구를 먼저 설치한 다음 위에서 언급한 명령을 다시 실행해야 한다.
kubectl cluster-info가 URL 응답을 반환하지만 클러스터에 접근할 수 없는 경우, 올바르게 구성되었는지 확인하려면 다음을 사용한다.
kubectl cluster-info dump
이것은 쿠버네티스 커맨드 라인 도구인 kubectl
의 플러그인으로서, 특정 버전의 쿠버네티스 API로 작성된 매니페스트를 다른 버전으로
변환할 수 있도록 한다. 이것은 매니페스트를 최신 쿠버네티스 릴리스의 사용 중단되지 않은 API로 마이그레이션하는 데 특히 유용하다.
더 많은 정보는 다음의 사용 중단되지 않은 API로 마이그레이션을 참고한다.
Bash의 kubectl 자동 완성 스크립트는 kubectl completion bash
로 생성할 수 있다. 이 스크립트를 셸에 소싱하면 kubectl 자동 완성이 가능하다.
그러나 kubectl 자동 완성 스크립트는 미리 bash-completion을 설치해야 동작한다.
여기의 지침에서는 Bash 4.1 이상을 사용한다고 가정한다. 다음을 실행하여 Bash 버전을 확인할 수 있다.
echo $BASH_VERSION
너무 오래된 버전인 경우, Homebrew를 사용하여 설치/업그레이드할 수 있다.
brew install bash
셸을 다시 로드하고 원하는 버전을 사용 중인지 확인한다.
echo $BASH_VERSION $SHELL
Homebrew는 보통 /usr/local/bin/bash
에 설치한다.
bash-completion v2가 이미 설치되어 있는지 type_init_completion
으로 확인할 수 있다. 그렇지 않은 경우, Homebrew로 설치할 수 있다.
brew install bash-completion@2
이 명령의 출력에 명시된 바와 같이, ~/.bash_profile
파일에 다음을 추가한다.
export BASH_COMPLETION_COMPAT_DIR="/usr/local/etc/bash_completion.d"
[[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"
셸을 다시 로드하고 bash-completion v2가 올바르게 설치되었는지 type _init_completion
으로 확인한다.
이제 kubectl 자동 완성 스크립트가 모든 셸 세션에서 제공되도록 해야 한다. 이를 수행하는 방법에는 여러 가지가 있다.
자동 완성 스크립트를 ~/.bash_profile
파일에서 소싱한다.
echo 'source <(kubectl completion bash)' >>~/.bash_profile
자동 완성 스크립트를 /usr/local/etc/bash_completion.d
디렉터리에 추가한다.
kubectl completion bash >/usr/local/etc/bash_completion.d/kubectl
kubectl에 대한 앨리어스가 있는 경우, 해당 앨리어스로 작업하기 위해 셸 자동 완성을 확장할 수 있다.
echo 'alias k=kubectl' >>~/.bash_profile
echo 'complete -F __start_kubectl k' >>~/.bash_profile
Homebrew로 kubectl을 설치한 경우(여기의 설명을 참고), kubectl 자동 완성 스크립트가 이미 /usr/local/etc/bash_completion.d/kubectl
에 있을 것이다. 이 경우, 아무 것도 할 필요가 없다.
BASH_COMPLETION_COMPAT_DIR
디렉터리의 모든 파일을 소싱하므로, 후자의 두 가지 방법이 적용된다.어떤 경우든, 셸을 다시 로드하면, kubectl 자동 완성 기능이 작동할 것이다.
PowerShell용 kubectl 자동 완성 스크립트는 kubectl completion powershell
명령으로 생성할 수 있다.
모든 셸 세션에서 사용하려면, $PROFILE
파일에 다음을 추가한다.
kubectl completion powershell | Out-String | Invoke-Expression
이 명령은 PowerShell을 실행할 때마다 자동 완성 스크립트를 재생성한다. 아니면, 생성된 스크립트를 $PROFILE
파일에 직접 추가할 수도 있다.
생성된 스크립트를 $PROFILE
파일에 직접 추가하려면, PowerShell 프롬프트에서 다음 명령줄을 실행한다.
kubectl completion powershell >> $PROFILE
셸을 다시 불러오면, kubectl 자동 완성이 동작할 것이다.
Zsh용 kubectl 자동 완성 스크립트는 kubectl completion zsh
명령으로 생성할 수 있다. 셸에서 자동 완성 스크립트를 소싱하면 kubectl 자동 완성 기능이 활성화된다.
모든 셸 세션에서 사용하려면, ~/.zshrc
파일에 다음을 추가한다.
source <(kubectl completion zsh)
kubectl에 대한 앨리어스가 있는 경우, 해당 앨리어스로 작업하도록 셸 자동 완성을 확장할 수 있다.
echo 'alias k=kubectl' >>~/.zshrc
echo 'compdef __start_kubectl k' >>~/.zshrc
셸을 다시 로드하면, kubectl 자동 완성 기능이 작동할 것이다.
complete:13: command not found: compdef
와 같은 오류가 발생하면, ~/.zshrc
파일의 시작 부분에 다음을 추가한다.
autoload -Uz compinit
compinit
Bash의 kubectl 자동 완성 스크립트는 kubectl completion bash
명령으로 생성할 수 있다. 셸에서 자동 완성 스크립트를 소싱(sourcing)하면 kubectl 자동 완성 기능이 활성화된다.
그러나, 자동 완성 스크립트는 bash-completion에 의존하고 있으며, 이 소프트웨어를 먼저 설치해야 한다(type _init_completion
을 실행하여 bash-completion이 이미 설치되어 있는지 확인할 수 있음).
bash-completion은 많은 패키지 관리자에 의해 제공된다(여기 참고). apt-get install bash-completion
또는 yum install bash-completion
등으로 설치할 수 있다.
위의 명령은 bash-completion의 기본 스크립트인 /usr/share/bash-completion/bash_completion
을 생성한다. 패키지 관리자에 따라, ~/.bashrc
파일에서 이 파일을 수동으로 소스(source)해야 한다.
확인하려면, 셸을 다시 로드하고 type _init_completion
을 실행한다. 명령이 성공하면, 이미 설정된 상태이고, 그렇지 않으면 ~/.bashrc
파일에 다음을 추가한다.
source /usr/share/bash-completion/bash_completion
셸을 다시 로드하고 type _init_completion
을 입력하여 bash-completion이 올바르게 설치되었는지 확인한다.
이제 kubectl 자동 완성 스크립트가 모든 셸 세션에서 제공되도록 해야 한다. 이를 수행할 수 있는 두 가지 방법이 있다.
echo 'source <(kubectl completion bash)' >>~/.bashrc
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null
kubectl에 대한 앨리어스(alias)가 있는 경우, 해당 앨리어스로 작업하도록 셸 자동 완성을 확장할 수 있다.
echo 'alias k=kubectl' >>~/.bashrc
echo 'complete -F __start_kubectl k' >>~/.bashrc
/etc/bash_completion.d
에 있는 모든 자동 완성 스크립트를 소싱한다.두 방법 모두 동일하다. 셸을 다시 로드하면, kubectl 자동 완성 기능이 작동할 것이다.
Kubernetes v1.15 [stable]
kubeadm으로 생성된 클라이언트 인증서는 1년 후에 만료된다. 이 페이지는 kubeadm으로 인증서 갱신을 관리하는 방법을 설명한다.
쿠버네티스의 PKI 인증서와 요구 조건에 익숙해야 한다.
기본적으로, kubeadm은 클러스터를 실행하는 데 필요한 모든 인증서를 생성한다. 사용자는 자체 인증서를 제공하여 이 동작을 무시할 수 있다.
이렇게 하려면, --cert-dir
플래그 또는 kubeadm ClusterConfiguration
의
certificatesDir
필드에 지정된 디렉터리에 배치해야 한다.
기본적으로 /etc/kubernetes/pki
이다.
kubeadm init
을 실행하기 전에 지정된 인증서와 개인 키(private key) 쌍이 존재하면,
kubeadm은 이를 덮어 쓰지 않는다. 이는 예를 들어, 기존 CA를
/etc/kubernetes/pki/ca.crt
와 /etc/kubernetes/pki/ca.key
에
복사할 수 있고, kubeadm은 이 CA를 사용하여 나머지 인증서에 서명한다는 걸 의미한다.
ca.key
파일이 아닌 ca.crt
파일만 제공할
수도 있다(이는 다른 인증서 쌍이 아닌 루트 CA 파일에만 사용 가능함).
다른 모든 인증서와 kubeconfig 파일이 있으면, kubeadm은 이 조건을
인식하고 "외부 CA" 모드를 활성화한다. kubeadm은 디스크에
CA 키없이 진행한다.
대신, --controllers=csrsigner
사용하여 controller-manager를
독립적으로 실행하고 CA 인증서와 키를 가리킨다.
PKI 인증서와 요구 조건은 외부 CA를 사용하도록 클러스터 설정에 대한 지침을 포함한다.
check-expiration
하위 명령을 사용하여 인증서가 만료되는 시기를 확인할 수 있다.
kubeadm certs check-expiration
출력 결과는 다음과 비슷하다.
CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
admin.conf Dec 30, 2020 23:36 UTC 364d no
apiserver Dec 30, 2020 23:36 UTC 364d ca no
apiserver-etcd-client Dec 30, 2020 23:36 UTC 364d etcd-ca no
apiserver-kubelet-client Dec 30, 2020 23:36 UTC 364d ca no
controller-manager.conf Dec 30, 2020 23:36 UTC 364d no
etcd-healthcheck-client Dec 30, 2020 23:36 UTC 364d etcd-ca no
etcd-peer Dec 30, 2020 23:36 UTC 364d etcd-ca no
etcd-server Dec 30, 2020 23:36 UTC 364d etcd-ca no
front-proxy-client Dec 30, 2020 23:36 UTC 364d front-proxy-ca no
scheduler.conf Dec 30, 2020 23:36 UTC 364d no
CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
ca Dec 28, 2029 23:36 UTC 9y no
etcd-ca Dec 28, 2029 23:36 UTC 9y no
front-proxy-ca Dec 28, 2029 23:36 UTC 9y no
이 명령은 /etc/kubernetes/pki
폴더의 클라이언트 인증서와 kubeadm이 사용하는 KUBECONFIG 파일(admin.conf
, controller-manager.conf
및 scheduler.conf
)에 포함된 클라이언트 인증서의 만료/잔여 기간을 표시한다.
또한, kubeadm은 인증서가 외부에서 관리되는지를 사용자에게 알린다. 이 경우 사용자는 수동으로 또는 다른 도구를 사용해서 인증서 갱신 관리를 해야 한다.
kubeadm
은 외부 CA가 서명한 인증서를 관리할 수 없다.kubelet.conf
는 위 목록에 포함되어 있지 않은데, 이는
kubeadm이 자동 인증서 갱신을 위해
/var/lib/kubelet/pki
에 있는 갱신 가능한 인증서를 이용하여 kubelet을 구성하기 때문이다.
만료된 kubelet 클라이언트 인증서를 갱신하려면
kubelet 클라이언트 갱신 실패 섹션을 확인한다.kubeadm 1.17 이전의 버전에서 kubeadm init
으로 작성된 노드에는
kubelet.conf
의 내용을 수동으로 수정해야 하는 버그가 있다. kubeadm init
수행 완료 후, client-certificate-data
및 client-key-data
를 다음과 같이 교체하여,
로테이트된 kubelet 클라이언트 인증서를 가리키도록 kubelet.conf
를 업데이트해야 한다.
client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
kubeadm은 컨트롤 플레인 업그레이드 동안 모든 인증서를 갱신한다.
이 기능은 가장 간단한 유스케이스를 해결하기 위해 설계되었다. 인증서 갱신에 대해 특별한 요구 사항이 없고 쿠버네티스 버전 업그레이드를 정기적으로(매 1년 이내 업그레이드 수행) 수행하는 경우, kubeadm은 클러스터를 최신 상태로 유지하고 합리적으로 보안을 유지한다.
인증서 갱신에 대해 보다 복잡한 요구 사항이 있는 경우, --certificate-renewal=false
를 kubeadm upgrade apply
또는 kubeadm upgrade node
와 함께 사용하여 기본 동작이 수행되지 않도록 할 수 있다.
kubeadm upgrade node
명령에서
--certificate-renewal
의 기본값이 false
인 버그가
있다. 이 경우 --certificate-renewal=true
를 명시적으로 설정해야 한다.kubeadm certs renew
명령을 사용하여 언제든지 인증서를 수동으로 갱신할 수 있다.
이 명령은 /etc/kubernetes/pki
에 저장된 CA(또는 프론트 프록시 CA) 인증서와 키를 사용하여 갱신을 수행한다.
명령을 실행한 후에는 컨트롤 플레인 파드를 재시작해야 한다.
이는 현재 일부 구성 요소 및 인증서에 대해 인증서를 동적으로 다시 로드하는 것이 지원되지 않기 때문이다.
스태틱(static) 파드는 API 서버가 아닌 로컬 kubelet에서 관리되므로
kubectl을 사용하여 삭제 및 재시작할 수 없다.
스태틱 파드를 다시 시작하려면 /etc/kubernetes/manifests/
에서 매니페스트 파일을 일시적으로 제거하고
20초를 기다리면 된다 (KubeletConfiguration struct의 fileCheckFrequency
값을 참고한다).
파드가 매니페스트 디렉터리에 더 이상 없는 경우 kubelet은 파드를 종료한다.
그런 다음 파일을 다시 이동할 수 있으며 또 다른 fileCheckFrequency
기간이 지나면,
kubelet은 파드를 생성하고 구성 요소에 대한 인증서 갱신을 완료할 수 있다.
certs renew
는 기존 인증서를 kubeadm-config 컨피그맵(ConfigMap) 대신 속성(공통 이름, 조직, SAN 등)의 신뢰할 수 있는 소스로 사용한다. 둘 다 동기화 상태를 유지하는 것을 강력히 권장한다.kubeadm certs renew
는 다음의 옵션을 제공한다.
쿠버네티스 인증서는 일반적으로 1년 후 만료일에 도달한다.
--csr-only
는 실제로 인증서를 갱신하지 않고 인증서 서명 요청을 생성하여 외부 CA로 인증서를 갱신하는 데 사용할 수 있다. 자세한 내용은 다음 단락을 참고한다.
모든 인증서 대신 단일 인증서를 갱신할 수도 있다.
이 섹션에서는 쿠버네티스 인증서 API를 사용하여 수동 인증서 갱신을 실행하는 방법에 대한 자세한 정보를 제공한다.
쿠버네티스 인증 기관(Certificate Authority)은 기본적으로 작동하지 않는다. cert-manager와 같은 외부 서명자를 설정하거나, 빌트인 서명자를 사용할 수 있다.
빌트인 서명자는 kube-controller-manager
의 일부이다.
빌트인 서명자를 활성화하려면, --cluster-signing-cert-file
와 --cluster-signing-key-file
플래그를 전달해야 한다.
새 클러스터를 생성하는 경우, kubeadm 구성 파일을 사용할 수 있다.
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
controllerManager:
extraArgs:
cluster-signing-cert-file: /etc/kubernetes/pki/ca.crt
cluster-signing-key-file: /etc/kubernetes/pki/ca.key
쿠버네티스 API로 CSR을 작성하려면 CertificateSigningRequest 생성을 본다.
이 섹션에서는 외부 CA를 사용하여 수동 인증서 갱신을 실행하는 방법에 대한 자세한 정보를 제공한다.
외부 CA와 보다 효과적으로 통합하기 위해 kubeadm은 인증서 서명 요청(CSR)을 생성할 수도 있다. CSR은 클라이언트의 서명된 인증서에 대한 CA 요청을 나타낸다. kubeadm 관점에서, 일반적으로 온-디스크(on-disk) CA에 의해 서명되는 모든 인증서는 CSR로 생성될 수 있다. 그러나 CA는 CSR로 생성될 수 없다.
kubeadm certs renew --csr-only
로 인증서 서명 요청을 만들 수 있다.
CSR과 함께 제공되는 개인 키가 모두 출력된다.
--csr-dir
로 사용할 디텍터리를 전달하여 지정된 위치로 CSR을 출력할 수 있다.
--csr-dir
을 지정하지 않으면, 기본 인증서 디렉터리(/etc/kubernetes/pki
)가 사용된다.
kubeadm certs renew --csr-only
로 인증서를 갱신할 수 있다.
kubeadm init
과 마찬가지로 출력 디렉터리를 --csr-dir
플래그로 지정할 수 있다.
CSR에는 인증서 이름, 도메인 및 IP가 포함되지만, 용도를 지정하지는 않는다. 인증서를 발행할 때 올바른 인증서 용도를 지정하는 것은 CA의 책임이다.
openssl
의 경우
openssl ca
명령으로 수행한다.cfssl
의 경우
설정 파일에 용도를 지정한다.선호하는 방법으로 인증서에 서명한 후, 인증서와 개인 키를 PKI 디렉터리(기본적으로 /etc/kubernetes/pki
)에 복사해야 한다.
Kubeadm은 CA 인증서의 순환이나 교체 기능을 기본적으로 지원하지 않는다.
CA의 수동 순환이나 교체에 대한 보다 상세한 정보는 CA 인증서 수동 순환 문서를 참조한다.
기본적으로 kubeadm에 의해서 배포된 kubelet 인증서는 자가 서명된(self-signed) 것이다. 이것은 metrics-server와 같은 외부 서비스의 kubelet에 대한 연결은 TLS로 보안되지 않음을 의미한다.
제대로 서명된 인증서를 얻기 위해서 신규 kubeadm 클러스터의 kubelet을 구성하려면
다음의 최소 구성을 kubeadm init
에 전달해야 한다.
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
serverTLSBootstrap: true
만약 이미 클러스터를 생성했다면 다음을 따라 이를 조정해야 한다.
kube-system
네임스페이스에서 kubelet-config-1.24
컨피그맵을 찾아서 수정한다.
해당 컨피그맵에는 kubelet
키가
KubeletConfiguration
문서를 값으로 가진다. serverTLSBootstrap: true
가 되도록 KubeletConfiguration 문서를 수정한다.serverTLSBootstrap: true
필드를 /var/lib/kubelet/config.yaml
에 추가한다.
그리고 systemctl restart kubelet
로 kubelet을 재시작한다.serverTLSBootstrap: true
필드는 kubelet 인증서를 이용한 부트스트랩을
certificates.k8s.io
API에 요청함으로써 활성화할 것이다. 한 가지 알려진 제약은
이 인증서들에 대한 CSR(인증서 서명 요청)들이 kube-controller-manager -
kubernetes.io/kubelet-serving
의
기본 서명자(default signer)에 의해서 자동으로 승인될 수 없다는 점이다.
이것은 사용자나 제 3의 컨트롤러의 액션을 필요로 할 것이다.
이 CSR들은 다음을 통해 볼 수 있다.
kubectl get csr
NAME AGE SIGNERNAME REQUESTOR CONDITION
csr-9wvgt 112s kubernetes.io/kubelet-serving system:node:worker-1 Pending
csr-lz97v 1m58s kubernetes.io/kubelet-serving system:node:control-plane-1 Pending
이를 승인하기 위해서는 다음을 수행한다.
kubectl certificate approve <CSR-name>
기본적으로, 이 인증서는 1년 후에 만기될 것이다. Kubeadm은
KubeletConfiguration
필드의 rotateCertificates
를 true
로 설정한다. 이것은 만기가
다가오면 인증서를 위한 신규 CSR 세트가 생성되는 것을 의미하며,
해당 순환(rotation)을 완료하기 위해서는 승인이 되어야 한다는 것을 의미한다. 더 상세한 이해를 위해서는
인증서 순환를 확인한다.
만약 이 CSR들의 자동 승인을 위한 솔루션을 찾고 있다면 클라우드 제공자와 연락하여 대역 외 메커니즘(out of band mechanism)을 통해 노드의 신분을 검증할 수 있는 CSR 서명자를 가지고 있는지 문의하는 것을 추천한다.
써드파티 커스텀 컨트롤러도 사용될 수 있다.
이러한 컨트롤러는 CSR의 CommonName과 요청된 IPs 및 도메인 네임을 모두 검증하지 않는 한, 보안이 되는 메커니즘이 아니다. 이것을 통해 악의적 행위자가 kubelet 인증서(클라이언트 인증)를 사용하여 아무 IP나 도메인 네임에 대해 인증서를 요청하는 CSR의 생성을 방지할 수 있을 것이다.
이 페이지는 kubeadm으로 생성된 쿠버네티스 클러스터를
1.23.x 버전에서 1.24.x 버전으로,
1.24.x 버전에서 1.24.y(여기서 y > x
) 버전으로 업그레이드하는 방법을 설명한다. 업그레이드가 지원되지 않는 경우
마이너 버전을 건너뛴다.
이전 버전의 kubeadm을 사용하여 생성된 클러스터 업그레이드에 대한 정보를 보려면, 이 페이지 대신 다음의 페이지들을 참고한다.
추상적인 업그레이드 작업 절차는 다음과 같다.
kubeadm upgrade
는 워크로드에 영향을 미치지 않고, 쿠버네티스 내부의 컴포넌트만 다루지만, 백업은 항상 모범 사례일 정도로 중요하다.OS 패키지 관리자를 사용하여 쿠버네티스의 최신 패치 릴리스 버전(1.24)을 찾는다.
apt update
apt-cache madison kubeadm
# 목록에서 최신 버전(1.24)을 찾는다
# 1.24.x-00과 같아야 한다. 여기서 x는 최신 패치이다.
yum list --showduplicates kubeadm --disableexcludes=kubernetes
# 목록에서 최신 버전(1.24)을 찾는다
# 1.24.x-0과 같아야 한다. 여기서 x는 최신 패치이다.
컨트롤 플레인 노드의 업그레이드 절차는 한 번에 한 노드씩 실행해야 한다.
먼저 업그레이드할 컨트롤 플레인 노드를 선택한다. /etc/kubernetes/admin.conf
파일이 있어야 한다.
첫 번째 컨트롤 플레인 노드의 경우
# 1.24.x-00에서 x를 최신 패치 버전으로 바꾼다.
apt-mark unhold kubeadm && \
apt-get update && apt-get install -y kubeadm=1.24.x-00 && \
apt-mark hold kubeadm
# 1.24.x-0에서 x를 최신 패치 버전으로 바꾼다.
yum install -y kubeadm-1.24.x-0 --disableexcludes=kubernetes
다운로드하려는 버전이 잘 받아졌는지 확인한다.
kubeadm version
업그레이드 계획을 확인한다.
kubeadm upgrade plan
이 명령은 클러스터를 업그레이드할 수 있는지를 확인하고, 업그레이드할 수 있는 버전을 가져온다. 또한 컴포넌트 구성 버전 상태가 있는 표를 보여준다.
kubeadm upgrade
는 이 노드에서 관리하는 인증서를 자동으로 갱신한다.
인증서 갱신을 하지 않으려면 --certificate-renewal=false
플래그를 사용할 수 있다.
자세한 내용은 인증서 관리 가이드를 참고한다.kubeadm upgrade plan
이 수동 업그레이드가 필요한 컴포넌트 구성을 표시하는 경우, 사용자는
--config
커맨드 라인 플래그를 통해 대체 구성이 포함된 구성 파일을 kubeadm upgrade apply
에 제공해야 한다.
그렇게 하지 않으면 kubeadm upgrade apply
가 오류와 함께 종료되고 업그레이드를 수행하지 않는다.업그레이드할 버전을 선택하고, 적절한 명령을 실행한다. 예를 들면 다음과 같다.
# 이 업그레이드를 위해 선택한 패치 버전으로 x를 바꾼다.
sudo kubeadm upgrade apply v1.24.x
명령이 완료되면 다음을 확인해야 한다.
[upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.24.x". Enjoy!
[upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.
CNI 제공자 플러그인을 수동으로 업그레이드한다.
CNI(컨테이너 네트워크 인터페이스) 제공자는 자체 업그레이드 지침을 따를 수 있다. 애드온 페이지에서 사용하는 CNI 제공자를 찾고 추가 업그레이드 단계가 필요한지 여부를 확인한다.
CNI 제공자가 데몬셋(DaemonSet)으로 실행되는 경우 추가 컨트롤 플레인 노드에는 이 단계가 필요하지 않다.
다른 컨트롤 플레인 노드의 경우
첫 번째 컨트롤 플레인 노드와 동일하지만 다음을 사용한다.
sudo kubeadm upgrade node
아래 명령 대신 위의 명령을 사용한다.
sudo kubeadm upgrade apply
kubeadm upgrade plan
을 호출하고 CNI 공급자 플러그인을 업그레이드할 필요가 없다.
Prepare the node for maintenance by marking it unschedulable and evicting the workloads:
# <node-to-drain>을 드레인하는 노드의 이름으로 바꾼다.
kubectl drain <node-to-drain> --ignore-daemonsets
# replace x in 1.24.x-00의 x를 최신 패치 버전으로 바꾼다
apt-mark unhold kubelet kubectl && \
apt-get update && apt-get install -y kubelet=1.24.x-00 kubectl=1.24.x-00 && \
apt-mark hold kubelet kubectl
# 1.24.x-0에서 x를 최신 패치 버전으로 바꾼다
yum install -y kubelet-1.24.x-0 kubectl-1.24.x-0 --disableexcludes=kubernetes
sudo systemctl daemon-reload
sudo systemctl restart kubelet
노드를 스케줄 가능으로 표시하여 노드를 다시 온라인 상태로 전환한다.
# <node-to-drain>을 드레인하는 노드의 이름으로 바꾼다.
kubectl uncordon <node-to-drain>
워커 노드의 업그레이드 절차는 워크로드를 실행하는 데 필요한 최소 용량을 보장하면서, 한 번에 하나의 노드 또는 한 번에 몇 개의 노드로 실행해야 한다.
# 1.24.x-00의 x를 최신 패치 버전으로 바꾼다
apt-mark unhold kubeadm && \
apt-get update && apt-get install -y kubeadm=1.24.x-00 && \
apt-mark hold kubeadm
# 1.24.x-0에서 x를 최신 패치 버전으로 바꾼다
yum install -y kubeadm-1.24.x-0 --disableexcludes=kubernetes
워커 노드의 경우 로컬 kubelet 구성을 업그레이드한다.
sudo kubeadm upgrade node
스케줄 불가능(unschedulable)으로 표시하고 워크로드를 축출하여 유지 보수할 노드를 준비한다.
# <node-to-drain>을 드레이닝하려는 노드 이름으로 바꾼다.
kubectl drain <node-to-drain> --ignore-daemonsets
# 1.24.x-00의 x를 최신 패치 버전으로 바꾼다
apt-mark unhold kubelet kubectl && \
apt-get update && apt-get install -y kubelet=1.24.x-00 kubectl=1.24.x-00 && \
apt-mark hold kubelet kubectl
# 1.24.x-0에서 x를 최신 패치 버전으로 바꾼다
yum install -y kubelet-1.24.x-0 kubectl-1.24.x-0 --disableexcludes=kubernetes
kubelet을 다시 시작한다.
sudo systemctl daemon-reload
sudo systemctl restart kubelet
스케줄 가능(schedulable)으로 표시하여 노드를 다시 온라인 상태로 만든다.
# <node-to-drain>을 노드의 이름으로 바꾼다.
kubectl uncordon <node-to-drain>
모든 노드에서 kubelet을 업그레이드한 후 kubectl이 클러스터에 접근할 수 있는 곳에서 다음의 명령을 실행하여 모든 노드를 다시 사용할 수 있는지 확인한다.
kubectl get nodes
모든 노드에 대해 STATUS
열에 Ready
가 표시되어야 하고, 버전 번호가 업데이트되어 있어야 한다.
예를 들어 kubeadm upgrade
를 실행하는 중에 예기치 못한 종료로 인해 업그레이드가 실패하고 롤백하지 않는다면, kubeadm upgrade
를 다시 실행할 수 있다.
이 명령은 멱등성을 보장하며 결국 실제 상태가 선언한 의도한 상태인지 확인한다.
잘못된 상태에서 복구하기 위해, 클러스터가 실행 중인 버전을 변경하지 않고 kubeadm upgrade apply --force
를 실행할 수도 있다.
업그레이드하는 동안 kubeadm은 /etc/kubernetes/tmp
아래에 다음과 같은 백업 폴더를 작성한다.
kubeadm-backup-etcd-<date>-<time>
kubeadm-backup-manifests-<date>-<time>
kubeadm-backup-etcd
는 컨트롤 플레인 노드에 대한 로컬 etcd 멤버 데이터의 백업을 포함한다.
etcd 업그레이드가 실패하고 자동 롤백이 작동하지 않으면, 이 폴더의 내용을
/var/lib/etcd
에서 수동으로 복원할 수 있다. 외부 etcd를 사용하는 경우 이 백업 폴더는 비어있다.
kubeadm-backup-manifests
는 컨트롤 플레인 노드에 대한 정적 파드 매니페스트 파일의 백업을 포함한다.
업그레이드가 실패하고 자동 롤백이 작동하지 않으면, 이 폴더의 내용을
/etc/kubernetes/manifests
에서 수동으로 복원할 수 있다. 어떤 이유로 특정 컴포넌트의 업그레이드 전
매니페스트 파일과 업그레이드 후 매니페스트 파일 간에 차이가 없는 경우, 백업 파일은 기록되지 않는다.
kubeadm upgrade apply
는 다음을 수행한다.
Ready
상태에 있다CoreDNS
와 kube-proxy
매니페스트를 적용하고 필요한 모든 RBAC 규칙이 생성되도록 한다.kubeadm upgrade node
는 추가 컨트롤 플레인 노드에서 다음을 수행한다.
ClusterConfiguration
을 가져온다.kubeadm upgrade node
는 워커 노드에서 다음을 수행한다.
ClusterConfiguration
을 가져온다.Kubernetes v1.18 [beta]
쿠버네티스를 사용하여 리눅스와 윈도우 노드를 혼합하여 실행할 수 있으므로, 리눅스에서 실행되는 파드와 윈도우에서 실행되는 파드를 혼합할 수 있다. 이 페이지는 윈도우 노드를 클러스터에 등록하는 방법을 보여준다.
kubectl version
.윈도우 컨테이너를 호스팅하는 윈도우 노드를 구성하려면 윈도우 서버 2019 라이선스 이상이 필요하다. VXLAN/오버레이 네트워킹을 사용하는 경우 KB4489899도 설치되어 있어야 한다.
컨트롤 플레인에 접근할 수 있는 리눅스 기반의 쿠버네티스 kubeadm 클러스터(kubeadm을 사용하여 단일 컨트롤 플레인 클러스터 생성 참고)가 필요하다.
리눅스 기반 쿠버네티스 컨트롤 플레인 노드가 있으면 네트워킹 솔루션을 선택할 수 있다. 이 가이드는 VXLAN 모드의 플란넬(Flannel)을 사용하는 방법을 짧막하게 보여준다.
플란넬을 위한 쿠버네티스 컨트롤 플레인 준비
클러스터의 쿠버네티스 컨트롤 플레인에서 약간의 준비가 필요하다. 플란넬을 사용할 때 iptables 체인에 브릿지된 IPv4 트래픽을 활성화하는 것을 권장한다. 아래 명령을 모든 리눅스 노드에서 실행해야만 한다.
sudo sysctl net.bridge.bridge-nf-call-iptables=1
리눅스용 플란넬 다운로드 및 구성
가장 최근의 플란넬 매니페스트를 다운로드한다.
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
VNI를 4096으로 설정하고 포트를 4789로 설정하려면 플란넬 매니페스트의 net-conf.json
섹션을 수정한다. 다음과 같을 것이다.
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan",
"VNI": 4096,
"Port": 4789
}
}
Type
의 값을 "host-gw"
로 변경하고 VNI
와 Port
를 생략한다.플란넬 매니페스트 적용 및 유효성 검사
플란넬 구성을 적용해보자.
kubectl apply -f kube-flannel.yml
몇 분 후에, 플란넬 파드 네트워크가 배포되었다면 모든 파드가 실행 중인 것으로 표시된다.
kubectl get pods -n kube-system
출력 결과에 리눅스 flannel 데몬셋(DaemonSet)이 실행 중인 것으로 나와야 한다.
NAMESPACE NAME READY STATUS RESTARTS AGE
...
kube-system kube-flannel-ds-54954 1/1 Running 0 1m
윈도우 플란넬 및 kube-proxy 데몬셋 추가
이제 윈도우 호환 버전의 플란넬과 kube-proxy를 추가할 수 있다. 호환 가능한 kube-proxy 버전을 얻으려면, 이미지의 태그를 대체해야 한다. 다음의 예시는 쿠버네티스 v1.24.0의 사용법을 보여주지만, 사용자의 배포에 맞게 버전을 조정해야 한다.
curl -L https://github.com/kubernetes-sigs/sig-windows-tools/releases/latest/download/kube-proxy.yml | sed 's/VERSION/v1.24.0/g' | kubectl apply -f -
kubectl apply -f https://github.com/kubernetes-sigs/sig-windows-tools/releases/latest/download/flannel-overlay.yml
윈도우 노드에서 이더넷이 아닌 다른 인터페이스(예: "Ethernet0 2")를 사용하는 경우, flannel-host-gw.yml이나 flannel-overlay.yml 파일에서 다음 라인을 수정한다.
wins cli process run --path /k/flannel/setup.exe --args "--mode=overlay --interface=Ethernet"
그리고, 이에 따라 인터페이스를 지정해야 한다.
# 예시
curl -L https://github.com/kubernetes-sigs/sig-windows-tools/releases/latest/download/flannel-overlay.yml | sed 's/Ethernet/Ethernet0 2/g' | kubectl apply -f -
컨테이너
기능 설치
Install-WindowsFeature -Name containers
도커 설치 자세한 내용은 도커 엔진 설치 - 윈도우 서버 엔터프라이즈에서 확인할 수 있다.
curl.exe -LO https://raw.githubusercontent.com/kubernetes-sigs/sig-windows-tools/master/kubeadm/scripts/PrepareNode.ps1
.\PrepareNode.ps1 -KubernetesVersion v1.24.0
kubeadm
실행하여 노드에 조인컨트롤 플레인 호스트에서 kubeadm init
실행할 때 제공된 명령을 사용한다.
이 명령이 더 이상 없거나, 토큰이 만료된 경우, kubeadm token create --print-join-command
(컨트롤 플레인 호스트에서)를 실행하여 새 토큰 및 조인 명령을 생성할 수 있다.
curl.exe -LO https://github.com/kubernetes-sigs/sig-windows-tools/releases/latest/download/Install-Containerd.ps1
.\Install-Containerd.ps1
특정 버전의 containerD를 설치하려면 -ContainerDVersion를 사용하여 버전을 지정한다.
# 예
.\Install-Containerd.ps1 -ContainerDVersion 1.4.1
윈도우 노드에서 이더넷(예: "Ethernet0 2")이 아닌 다른 인터페이스를 사용하는 경우, -netAdapterName
으로 이름을 지정한다.
# 예
.\Install-Containerd.ps1 -netAdapterName "Ethernet0 2"
curl.exe -LO https://raw.githubusercontent.com/kubernetes-sigs/sig-windows-tools/master/kubeadm/scripts/PrepareNode.ps1
.\PrepareNode.ps1 -KubernetesVersion v1.24.0 -ContainerRuntime containerD
kubeadm
실행하여 노드에 조인컨트롤 플레인 호스트에서 `kubeadm init` 실행할 때 제공된 명령을 사용한다.
이 명령이 더 이상 없거나, 토큰이 만료된 경우, `kubeadm token create --print-join-command`
(컨트롤 플레인 호스트에서)를 실행하여 새 토큰 및 조인 명령을 생성할 수 있다.
--cri-socket "npipe:////./pipe/containerd-containerd"
를 추가한다이제 다음을 실행하여 클러스터에서 윈도우 노드를 볼 수 있다.
kubectl get nodes -o wide
새 노드가 NotReady
상태인 경우 플란넬 이미지가 여전히 다운로드 중일 수 있다.
kube-system
네임스페이스에서 flannel 파드를 확인하여 이전과 같이 진행 상황을 확인할 수 있다.
kubectl -n kube-system get pods -l app=flannel
flannel 파드가 실행되면, 노드는 Ready
상태가 되고 워크로드를 처리할 수 있어야 한다.
Kubernetes v1.18 [beta]
이 페이지는 kubeadm으로 생성된 윈도우 노드를 업그레이드하는 방법을 설명한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
쿠버네티스 서버의 버전은 다음과 같거나 더 높아야 함. 버전: 1.17. 버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.윈도우 노드에서, kubeadm을 업그레이드한다.
# replace v1.24.0 with your desired version
curl.exe -Lo C:\k\kubeadm.exe https://dl.k8s.io//bin/windows/amd64/kubeadm.exe
쿠버네티스 API에 접근할 수 있는 머신에서, 스케줄 불가능한 것으로 표시하고 워크로드를 축출하여 유지 보수할 노드를 준비한다.
# <node-to-drain>을 드레이닝하려는 노드 이름으로 바꾼다
kubectl drain <node-to-drain> --ignore-daemonsets
다음과 비슷한 출력이 표시되어야 한다.
node/ip-172-31-85-18 cordoned
node/ip-172-31-85-18 drained
윈도우 노드에서, 다음의 명령을 호출하여 새 kubelet 구성을 동기화한다.
kubeadm upgrade node
윈도우 노드에서, kubelet을 업그레이드하고 다시 시작한다.
stop-service kubelet
curl.exe -Lo C:\k\kubelet.exe https://dl.k8s.io//bin/windows/amd64/kubelet.exe
restart-service kubelet
쿠버네티스 API에 접근할 수 있는 머신에서, 스케줄 가능으로 표시하여 노드를 다시 온라인으로 가져온다.
# <node-to-drain>을 노드의 이름으로 바꾼다
kubectl uncordon <node-to-drain>
쿠버네티스 API에 접근할 수 있는 머신에서, 다음을 실행하여, v1.24.0을 원하는 버전으로 다시 바꾼다.
curl -L https://github.com/kubernetes-sigs/sig-windows-tools/releases/latest/download/kube-proxy.yml | sed 's/VERSION/v1.24.0/g' | kubectl apply -f -
이 페이지는 네임스페이스에 대한 기본 메모리 요청량(request) 및 상한(limit)을 구성하는 방법을 보여준다.
쿠버네티스 클러스터를 여러 네임스페이스로 나눌 수 있다. 기본 메모리 상한이 설정되어 있는 네임스페이스에 파드를 생성했는데, 해당 파드의 모든 컨테이너에 메모리 상한이 명시되어 있지 않다면, 컨트롤 플레인이 해당 컨테이너에 기본 메모리 상한을 할당한다.
쿠버네티스는 이 문서의 뒷부분에서 설명하는 특정 조건에서 기본 메모리 요청량을 할당한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
클러스터에 네임스페이스를 생성할 수 있는 권한이 있어야 한다.
클러스터의 각 노드에는 최소 2GiB의 메모리가 있어야 한다.
이 연습에서 생성한 리소스가 클러스터의 다른 리소스와 격리되도록 네임스페이스를 생성한다.
kubectl create namespace default-mem-example
다음은 예시 리밋레인지에 대한 매니페스트이다. 이 매니페스트는 기본 메모리 요청량 및 기본 메모리 상한을 지정한다.
apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit-range
spec:
limits:
- default:
memory: 512Mi
defaultRequest:
memory: 256Mi
type: Container
default-mem-example 네임스페이스에 리밋레인지를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/memory-defaults.yaml --namespace=default-mem-example
이제 파드를 default-mem-example
네임스페이스에 생성하고,
해당 파드의 어떤 컨테이너도 자체 메모리 요청량(request)과 상한(limit)을 명시하지 않으면,
컨트롤 플레인이 해당 컨테이너에 메모리 요청량의 기본값(256 MiB)과
상한의 기본값(512 MiB)을 지정한다.
다음은 컨테이너가 하나인 파드의 매니페스트이다. 해당 컨테이너는 메모리 요청량과 상한을 지정하지 않는다.
apiVersion: v1
kind: Pod
metadata:
name: default-mem-demo
spec:
containers:
- name: default-mem-demo-ctr
image: nginx
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/memory-defaults-pod.yaml --namespace=default-mem-example
파드에 대한 자세한 정보를 본다.
kubectl get pod default-mem-demo --output=yaml --namespace=default-mem-example
출력 결과는 파드의 컨테이너에 256MiB의 메모리 요청량과 512MiB의 메모리 상한이 있음을 나타낸다. 이것은 리밋레인지에 의해 지정된 기본값이다.
containers:
- image: nginx
imagePullPolicy: Always
name: default-mem-demo-ctr
resources:
limits:
memory: 512Mi
requests:
memory: 256Mi
파드를 삭제한다.
kubectl delete pod default-mem-demo --namespace=default-mem-example
다음은 컨테이너가 하나인 파드의 매니페스트이다. 해당 컨테이너는 메모리 상한은 지정하지만, 요청량은 지정하지 않는다.
apiVersion: v1
kind: Pod
metadata:
name: default-mem-demo-2
spec:
containers:
- name: default-mem-demo-2-ctr
image: nginx
resources:
limits:
memory: "1Gi"
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/memory-defaults-pod-2.yaml --namespace=default-mem-example
파드에 대한 자세한 정보를 본다.
kubectl get pod default-mem-demo-2 --output=yaml --namespace=default-mem-example
출력 결과는 컨테이너의 메모리 요청량이 메모리 상한과 일치하도록 설정되었음을 보여준다. 참고로 컨테이너에는 기본 메모리 요청량의 값인 256Mi가 할당되지 않았다.
resources:
limits:
memory: 1Gi
requests:
memory: 1Gi
다음은 컨테이너가 하나인 파드의 예시 매니페스트이다. 해당 컨테이너는 메모리 요청량은 지정하지만, 상한은 지정하지 않는다.
apiVersion: v1
kind: Pod
metadata:
name: default-mem-demo-3
spec:
containers:
- name: default-mem-demo-3-ctr
image: nginx
resources:
requests:
memory: "128Mi"
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/memory-defaults-pod-3.yaml --namespace=default-mem-example
파드 사양을 확인한다.
kubectl get pod default-mem-demo-3 --output=yaml --namespace=default-mem-example
출력을 보면 컨테이너의 매니페스트에 명시한 값대로 컨테이너의 메모리 요청량이 설정된 것을 알 수 있다. 해당 컨테이너의 메모리 상한은 512 MiB로 설정되며, 이는 네임스페이스의 메모리 상한 기본값과 일치한다.
resources:
limits:
memory: 512Mi
requests:
memory: 128Mi
네임스페이스에 리소스 쿼터가 설정되어 있는 경우, 메모리 상한에 기본값을 설정하는 것이 좋다. 다음은 리소스 쿼터가 네임스페이스에 적용하는 두 가지 제한 사항이다.
리밋레인지를 추가할 때에는 다음을 고려해야 한다.
컨테이너를 갖고 있는 해당 네임스페이스의 파드가 자체 메모리 상한을 지정하지 않았다면, 컨트롤 플레인이 해당 컨테이너에 메모리 상한 기본값을 적용하며, 해당 파드는 메모리 리소스쿼터가 적용된 네임스페이스에서 실행되도록 허용될 수 있다.
네임스페이스를 삭제한다.
kubectl delete namespace default-mem-example
이 페이지는 네임스페이스에 대한 기본 CPU 요청량(request) 및 상한(limit)을 구성하는 방법을 보여준다.
쿠버네티스 클러스터를 여러 네임스페이스로 나눌 수 있다. 기본 CPU 상한이 설정되어 있는 네임스페이스에 파드를 생성했는데, 해당 파드의 모든 컨테이너에 CPU 상한이 명시되어 있지 않다면, 컨트롤 플레인이 해당 컨테이너에 기본 CPU 상한을 할당한다.
쿠버네티스는 기본 CPU 사용량을 할당하는데, 이는 이 페이지의 이후 부분에서 설명될 특정 조건 하에서만 수행된다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
클러스터에 네임스페이스를 생성할 수 있는 권한이 있어야 한다.
쿠버네티스에서 “1.0 CPU”가 무엇을 의미하는지 익숙하지 않다면, CPU의 의미를 참조한다.
이 연습에서 생성한 리소스가 클러스터의 나머지와 격리되도록 네임스페이스를 생성한다.
kubectl create namespace default-cpu-example
다음은 예시 리밋레인지에 대한 매니페스트이다. 이 매니페스트는 기본 CPU 요청량 및 기본 CPU 상한을 지정한다.
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-limit-range
spec:
limits:
- default:
cpu: 1
defaultRequest:
cpu: 0.5
type: Container
default-cpu-example 네임스페이스에 리밋레인지를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/cpu-defaults.yaml --namespace=default-cpu-example
이제 파드를 default-cpu-example
네임스페이스에 생성하고,
해당 파드의 어떤 컨테이너도 자체 CPU 요청량(request)과 상한(limit)을 명시하지 않으면,
컨트롤 플레인이 해당 컨테이너에 CPU 요청량의 기본값(0.5)과
상한의 기본값(1)을 지정한다.
다음은 컨테이너가 하나인 파드의 매니페스트이다. 해당 컨테이너는 CPU 요청량과 상한을 지정하지 않는다.
apiVersion: v1
kind: Pod
metadata:
name: default-cpu-demo
spec:
containers:
- name: default-cpu-demo-ctr
image: nginx
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/cpu-defaults-pod.yaml --namespace=default-cpu-example
파드의 사양을 확인한다.
kubectl get pod default-cpu-demo --output=yaml --namespace=default-cpu-example
출력을 보면 파드 내 유일한 컨테이너의 CPU 요청량이 500m cpu
("500 밀리cpu"로 읽을 수 있음)이고,
CPU 상한이 1 cpu
임을 알 수 있다.
이것은 리밋레인지에 의해 지정된 기본값이다.
containers:
- image: nginx
imagePullPolicy: Always
name: default-cpu-demo-ctr
resources:
limits:
cpu: "1"
requests:
cpu: 500m
다음은 컨테이너가 하나인 파드의 매니페스트이다. 해당 컨테이너는 CPU 상한은 지정하지만, 요청량은 지정하지 않는다.
apiVersion: v1
kind: Pod
metadata:
name: default-cpu-demo-2
spec:
containers:
- name: default-cpu-demo-2-ctr
image: nginx
resources:
limits:
cpu: "1"
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/cpu-defaults-pod-2.yaml --namespace=default-cpu-example
생성한 파드의 명세를 확인한다.
kubectl get pod default-cpu-demo-2 --output=yaml --namespace=default-cpu-example
출력 결과는 컨테이너의 CPU 요청량이 CPU 상한과 일치하도록 설정되었음을 보여준다.
참고로 컨테이너에는 CPU 요청량의 기본값인 0.5 cpu
가 할당되지 않았다.
resources:
limits:
cpu: "1"
requests:
cpu: "1"
다음은 컨테이너가 하나인 파드의 예시 매니페스트이다. 해당 컨테이너는 CPU 요청량은 지정하지만, 상한은 지정하지 않는다.
apiVersion: v1
kind: Pod
metadata:
name: default-cpu-demo-3
spec:
containers:
- name: default-cpu-demo-3-ctr
image: nginx
resources:
requests:
cpu: "0.75"
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/cpu-defaults-pod-3.yaml --namespace=default-cpu-example
생성한 파드의 명세를 확인한다.
kubectl get pod default-cpu-demo-3 --output=yaml --namespace=default-cpu-example
출력을 보면 파드 생성 시 명시한 값대로
컨테이너의 CPU 요청량이 설정된 것을 알 수 있다(다시 말해, 매니페스트와 일치한다).
그러나, 해당 컨테이너의 CPU 상한은 1 cpu
로 설정되며,
이는 네임스페이스의 CPU 상한 기본값이다.
resources:
limits:
cpu: "1"
requests:
cpu: 750m
네임스페이스에 리소스 쿼터가 설정되어 있는 경우, CPU 상한에 대해 기본값을 설정하는 것이 좋다. 다음은 CPU 리소스 쿼터가 네임스페이스에 적용하는 두 가지 제한 사항이다.
리밋레인지를 추가할 때에는 다음을 고려해야 한다.
컨테이너를 갖고 있는 해당 네임스페이스의 파드가 자체 CPU 상한을 지정하지 않았다면, 컨트롤 플레인이 해당 컨테이너에 CPU 상한 기본값을 적용하며, 해당 파드는 CPU 리소스쿼터가 적용된 네임스페이스에서 실행되도록 허용될 수 있다.
네임스페이스를 삭제한다.
kubectl delete namespace default-cpu-example
이 페이지는 네임스페이스에서 실행되는 컨테이너가 사용하는 메모리의 최솟값과 최댓값을 설정하는 방법을 보여준다. 리밋레인지(LimitRange) 오브젝트에 최소 및 최대 메모리 값을 지정한다. 파드가 리밋레인지에 의해 부과된 제약 조건을 충족하지 않으면, 네임스페이스에서 생성될 수 없다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
클러스터에 네임스페이스를 생성할 수 있는 권한이 있어야 한다.
클러스터의 각 노드에는 파드가 사용할 수 있는 메모리가 최소 1GiB 이상 있어야 한다.
이 연습에서 생성한 리소스가 클러스터의 나머지와 격리되도록 네임스페이스를 생성한다.
kubectl create namespace constraints-mem-example
다음은 리밋레인지의 예시 매니페스트이다.
apiVersion: v1
kind: LimitRange
metadata:
name: mem-min-max-demo-lr
spec:
limits:
- max:
memory: 1Gi
min:
memory: 500Mi
type: Container
리밋레인지를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints.yaml --namespace=constraints-mem-example
리밋레인지에 대한 자세한 정보를 본다.
kubectl get limitrange mem-min-max-demo-lr --namespace=constraints-mem-example --output=yaml
출력 결과는 예상대로 메모리의 최소 및 최대 제약 조건을 보여준다. 그러나 참고로 리밋레인지의 구성 파일에 기본값(default)을 지정하지 않아도 자동으로 생성된다.
limits:
- default:
memory: 1Gi
defaultRequest:
memory: 1Gi
max:
memory: 1Gi
min:
memory: 500Mi
type: Container
이제 constraints-mem-example
네임스페이스에 파드를 생성할 때마다,
쿠버네티스는 다음 단계를 수행한다.
해당 파드의 어떤 컨테이너도 자체 메모리 요청량(request)과 상한(limit)을 명시하지 않으면, 해당 컨테이너에 메모리 요청량과 상한의 기본값(default)을 지정한다.
해당 파드의 모든 컨테이너의 메모리 요청량이 최소 500 MiB 이상인지 확인한다.
해당 파드의 모든 컨테이너의 메모리 요청량이 1024 MiB(1 GiB)를 넘지 않는지 확인한다.
다음은 컨테이너가 하나인 파드의 매니페스트이다. 파드 명세 내에, 파드의 유일한 컨테이너는 600 MiB의 메모리 요청량 및 800 MiB의 메모리 상한을 지정하고 있다. 이는 리밋레인지에 의해 부과된 최소 및 최대 메모리 제약 조건을 충족시킨다.
apiVersion: v1
kind: Pod
metadata:
name: constraints-mem-demo
spec:
containers:
- name: constraints-mem-demo-ctr
image: nginx
resources:
limits:
memory: "800Mi"
requests:
memory: "600Mi"
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod.yaml --namespace=constraints-mem-example
파드가 실행 중이고 컨테이너의 상태가 정상인지 확인한다.
kubectl get pod constraints-mem-demo --namespace=constraints-mem-example
파드에 대한 자세한 정보를 본다.
kubectl get pod constraints-mem-demo --output=yaml --namespace=constraints-mem-example
출력을 보면 파드의 컨테이너의 메모리 요청량이 600 MiB이고 메모리 상한이 800 MiB임을 알 수 있다. 이는 리밋레인지에 의해 해당 네임스페이스에 부과된 제약 조건을 만족시킨다.
resources:
limits:
memory: 800Mi
requests:
memory: 600Mi
파드를 삭제한다.
kubectl delete pod constraints-mem-demo --namespace=constraints-mem-example
다음은 컨테이너가 하나인 파드의 매니페스트이다. 컨테이너는 800MiB의 메모리 요청량과 1.5GiB의 메모리 상한을 지정하고 있다.
apiVersion: v1
kind: Pod
metadata:
name: constraints-mem-demo-2
spec:
containers:
- name: constraints-mem-demo-2-ctr
image: nginx
resources:
limits:
memory: "1.5Gi"
requests:
memory: "800Mi"
파드 생성을 시도한다.
kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod-2.yaml --namespace=constraints-mem-example
결과를 보면 파드가 생성되지 않은 것을 확인할 수 있으며, 이는 해당 파드가 정의하고 있는 컨테이너가 허용된 것보다 더 많은 메모리를 요청하고 있기 때문이다.
Error from server (Forbidden): error when creating "examples/admin/resource/memory-constraints-pod-2.yaml":
pods "constraints-mem-demo-2" is forbidden: maximum memory usage per Container is 1Gi, but limit is 1536Mi.
다음은 컨테이너가 하나인 파드의 매니페스트이다. 컨테이너는 100MiB의 메모리 요청량과 800MiB의 메모리 상한을 지정하고 있다.
apiVersion: v1
kind: Pod
metadata:
name: constraints-mem-demo-3
spec:
containers:
- name: constraints-mem-demo-3-ctr
image: nginx
resources:
limits:
memory: "800Mi"
requests:
memory: "100Mi"
파드 생성을 시도한다.
kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod-3.yaml --namespace=constraints-mem-example
결과를 보면 파드가 생성되지 않은 것을 확인할 수 있으며, 이는 해당 파드가 정의하고 있는 컨테이너가 지정된 최저 메모리 요청량보다도 낮은 메모리 요청량을 지정하고 있기 때문이다.
Error from server (Forbidden): error when creating "examples/admin/resource/memory-constraints-pod-3.yaml":
pods "constraints-mem-demo-3" is forbidden: minimum memory usage per Container is 500Mi, but request is 100Mi.
다음은 컨테이너가 하나인 파드의 매니페스트이다. 해당 컨테이너는 메모리 요청량과 상한을 지정하지 않는다.
apiVersion: v1
kind: Pod
metadata:
name: constraints-mem-demo-4
spec:
containers:
- name: constraints-mem-demo-4-ctr
image: nginx
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/memory-constraints-pod-4.yaml --namespace=constraints-mem-example
파드에 대한 자세한 정보를 본다.
kubectl get pod constraints-mem-demo-4 --namespace=constraints-mem-example --output=yaml
출력을 보면 파드의 유일한 컨테이너에 대한 메모리 요청량이 1 GiB이고 메모리 상한도 1 GiB이다. 이 컨테이너는 어떻게 이런 값을 얻었을까?
resources:
limits:
memory: 1Gi
requests:
memory: 1Gi
파드가 해당 컨테이너에 대해 메모리 요청량과 상한을 지정하지 않았으므로, 클러스터가 리밋레인지로부터 메모리의 요청량과 상한 기본값을 적용하였다.
이는 곧 파드 정의에서 이 값들을 볼 수 있음을 의미한다.
kubectl describe
명령을 사용하여 확인할 수 있다.
# 출력에서 "Requests:" 섹션을 확인한다
kubectl describe pod constraints-mem-demo-4 --namespace=constraints-mem-example
이 시점에서, 파드는 실행 중일 수도 있고 아닐 수도 있다. 이 태스크의 전제 조건은 노드에 최소 1GiB의 메모리가 있어야 한다는 것이다. 각 노드에 1GiB의 메모리만 있는 경우, 노드에 할당할 수 있는 메모리가 1GiB의 메모리 요청량을 수용하기에 충분하지 않을 수 있다. 메모리가 2GiB인 노드를 사용하는 경우에는, 메모리가 1GiB 요청량을 수용하기에 충분할 것이다.
파드를 삭제한다.
kubectl delete pod constraints-mem-demo-4 --namespace=constraints-mem-example
리밋레인지에 의해 네임스페이스에 부과된 메모리의 최대 및 최소 제약 조건은 파드를 생성하거나 업데이트할 때만 적용된다. 리밋레인지를 변경해도, 이전에 생성된 파드에는 영향을 미치지 않는다.
클러스터 관리자는 파드가 사용할 수 있는 메모리 양에 제한을 둘 수 있다. 예를 들면 다음과 같다.
클러스터의 각 노드에는 2GiB의 메모리가 있다. 클러스터의 어떤 노드도 2GiB 이상의 요청량을 지원할 수 없으므로, 2GiB 이상의 메모리를 요청하는 파드를 수락하지 않으려고 한다.
클러스터는 운영 부서와 개발 부서에서 공유한다. 프로덕션 워크로드가 최대 8GiB의 메모리를 소비하도록 하려면, 개발 워크로드를 512MiB로 제한해야 한다. 프로덕션 및 개발을 위해 별도의 네임스페이스를 만들고, 각 네임스페이스에 메모리 제약 조건을 적용한다.
네임스페이스를 삭제한다.
kubectl delete namespace constraints-mem-example
이 페이지는 네임스페이스에서 컨테이너와 파드가 사용하는 CPU 리소스의 최솟값과 최댓값을 설정하는 방법을 보여준다. 리밋레인지(LimitRange) 오브젝트에 CPU의 최솟값과 최댓값을 지정한다. 리밋레인지에 의해 부과된 제약 조건을 파드가 충족하지 않으면, 해당 네임스페이스에 생성될 수 없다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
클러스터에 네임스페이스를 생성할 수 있는 권한이 있어야 한다.
태스크 예제를 실행하려면 클러스터에 적어도 1.0 CPU 이상이 사용 가능해야 한다. 쿠버네티스에서 “1 CPU”가 무엇을 의미하는지 알아보려면 CPU의 의미를 참조한다.
이 연습에서 생성한 리소스가 클러스터의 나머지와 격리되도록 네임스페이스를 생성한다.
kubectl create namespace constraints-cpu-example
다음은 리밋레인지에 대한 예시 매니페스트이다.
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-min-max-demo-lr
spec:
limits:
- max:
cpu: "800m"
min:
cpu: "200m"
type: Container
리밋레인지를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/cpu-constraints.yaml --namespace=constraints-cpu-example
리밋레인지에 대한 자세한 정보를 본다.
kubectl get limitrange cpu-min-max-demo-lr --output=yaml --namespace=constraints-cpu-example
출력 결과는 예상대로 CPU의 최소와 최대 제약 조건을 보여준다. 그러나 참고로 리밋레인지에 대한 구성 파일에 기본값을 지정하지 않아도 자동으로 생성된다.
limits:
- default:
cpu: 800m
defaultRequest:
cpu: 800m
max:
cpu: 800m
min:
cpu: 200m
type: Container
이제 constraints-cpu-example
네임스페이스에 파드를 생성할 때마다(또는
다른 쿠버네티스 API 클라이언트가 동일한 파드를 생성할 때마다), 쿠버네티스는 다음 단계를 수행한다.
해당 파드의 어떤 컨테이너도 자체 CPU 요청량(request)과 상한(limit)을 명시하지 않으면, 컨트롤 플레인이 해당 컨테이너에 CPU 요청량과 상한의 기본값(default)을 지정한다.
해당 파드의 모든 컨테이너가 200 millicpu 이상의 CPU 요청량을 지정하는지 확인한다.
해당 파드의 모든 컨테이너가 800 millicpu 이하의 CPU 상한을 지정하는지 확인한다.
LimitRange
오브젝트를 생성할 때, huge-pages
또는 GPU에도 상한을 지정할 수 있다. 그러나, 이 리소스들에 default
와 defaultRequest
가
모두 지정되어 있으면, 두 값은 같아야 한다.다음은 컨테이너가 하나인 파드의 매니페스트이다. 컨테이너 매니페스트는 500 millicpu의 CPU 요청량 및 800 millicpu의 CPU 상한을 지정하고 있다. 이는 리밋레인지에 의해 부과된 CPU의 최소와 최대 제약 조건을 충족시킨다.
apiVersion: v1
kind: Pod
metadata:
name: constraints-cpu-demo
spec:
containers:
- name: constraints-cpu-demo-ctr
image: nginx
resources:
limits:
cpu: "800m"
requests:
cpu: "500m"
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/cpu-constraints-pod.yaml --namespace=constraints-cpu-example
파드가 실행 중이고 컨테이너의 상태가 정상인지 확인한다.
kubectl get pod constraints-cpu-demo --namespace=constraints-cpu-example
파드에 대한 자세한 정보를 본다.
kubectl get pod constraints-cpu-demo --output=yaml --namespace=constraints-cpu-example
출력 결과는 파드 내 유일한 컨테이너의 CPU 요청량이 500 millicpu이고, CPU 상한이 800 millicpu임을 나타낸다. 이는 리밋레인지에 의해 부과된 제약 조건을 만족시킨다.
resources:
limits:
cpu: 800m
requests:
cpu: 500m
kubectl delete pod constraints-cpu-demo --namespace=constraints-cpu-example
다음은 컨테이너가 하나인 파드의 매니페스트이다. 컨테이너는 500 millicpu의 CPU 요청량과 1.5 cpu의 CPU 상한을 지정하고 있다.
apiVersion: v1
kind: Pod
metadata:
name: constraints-cpu-demo-2
spec:
containers:
- name: constraints-cpu-demo-2-ctr
image: nginx
resources:
limits:
cpu: "1.5"
requests:
cpu: "500m"
파드 생성을 시도한다.
kubectl apply -f https://k8s.io/examples/admin/resource/cpu-constraints-pod-2.yaml --namespace=constraints-cpu-example
결과를 보면 파드가 생성되지 않은 것을 확인할 수 있으며, 이는 해당 파드가 수용 불가능한 컨테이너를 정의하고 있기 때문이다. 해당 컨테이너가 수용 불가능한 이유는 너무 큰 CPU 상한을 지정하고 있기 때문이다.
Error from server (Forbidden): error when creating "examples/admin/resource/cpu-constraints-pod-2.yaml":
pods "constraints-cpu-demo-2" is forbidden: maximum cpu usage per Container is 800m, but limit is 1500m.
다음은 컨테이너가 하나인 파드의 매니페스트이다. 컨테이너는 100 millicpu의 CPU 요청량과 800 millicpu의 CPU 상한을 지정하고 있다.
apiVersion: v1
kind: Pod
metadata:
name: constraints-cpu-demo-3
spec:
containers:
- name: constraints-cpu-demo-3-ctr
image: nginx
resources:
limits:
cpu: "800m"
requests:
cpu: "100m"
파드 생성을 시도한다.
kubectl apply -f https://k8s.io/examples/admin/resource/cpu-constraints-pod-3.yaml --namespace=constraints-cpu-example
결과를 보면 파드가 생성되지 않은 것을 확인할 수 있으며, 이는 해당 파드가 수용 불가능한 컨테이너를 정의하고 있기 때문이다. 해당 컨테이너가 수용 불가능한 이유는 지정된 최저 CPU 상한보다도 낮은 CPU 상한을 지정하고 있기 때문이다.
Error from server (Forbidden): error when creating "examples/admin/resource/cpu-constraints-pod-3.yaml":
pods "constraints-cpu-demo-3" is forbidden: minimum cpu usage per Container is 200m, but request is 100m.
다음은 컨테이너가 하나인 파드의 매니페스트이다. 컨테이너는 CPU 요청량을 지정하지 않았으며, CPU 상한도 지정하지 않았다.
apiVersion: v1
kind: Pod
metadata:
name: constraints-cpu-demo-4
spec:
containers:
- name: constraints-cpu-demo-4-ctr
image: vish/stress
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/cpu-constraints-pod-4.yaml --namespace=constraints-cpu-example
파드에 대한 자세한 정보를 본다.
kubectl get pod constraints-cpu-demo-4 --namespace=constraints-cpu-example --output=yaml
출력을 보면 파드의 유일한 컨테이너에 대한 CPU 요청량이 800 millicpu이고, CPU 상한이 800 millicpu이다. 이 컨테이너는 어떻게 이런 값을 얻었을까?
resources:
limits:
cpu: 800m
requests:
cpu: 800m
컨테이너가 자체 CPU 요청량과 상한을 지정하지 않았으므로, 컨테이너가 이 네임스페이스에 대해 리밋레인지로부터 CPU 요청량과 상한의 기본값을 적용했다.
이 시점에서, 파드는 실행 중일 수도 있고 아닐 수도 있다. 이 태스크의 전제 조건은 클러스터에 1 CPU 이상 사용 가능해야 한다는 것이다. 각 노드에 1 CPU만 있는 경우, 노드에 할당할 수 있는 CPU가 800 millicpu의 요청량을 수용하기에 충분하지 않을 수 있다. 2 CPU인 노드를 사용하는 경우에는, CPU가 800 millicpu 요청량을 수용하기에 충분할 것이다.
파드를 삭제한다.
kubectl delete pod constraints-cpu-demo-4 --namespace=constraints-cpu-example
리밋레인지에 의해 네임스페이스에 부과된 CPU의 최대 및 최소 제약 조건은 파드를 생성하거나 업데이트할 때만 적용된다. 리밋레인지를 변경해도, 이전에 생성된 파드에는 영향을 미치지 않는다.
클러스터 관리자는 파드가 사용할 수 있는 CPU 리소스에 제한을 둘 수 있다. 예를 들면 다음과 같다.
클러스터의 각 노드에는 2 CPU가 있다. 클러스터의 어떤 노드도 요청량을 지원할 수 없기 때문에, 2 CPU 이상을 요청하는 파드를 수락하지 않으려고 한다.
클러스터는 프로덕션과 개발 부서에서 공유한다. 프로덕션 워크로드가 최대 3 CPU를 소비하도록 하고 싶지만, 개발 워크로드는 1 CPU로 제한하려고 한다. 프로덕션과 개발을 위해 별도의 네임스페이스를 생성하고, 각 네임스페이스에 CPU 제약 조건을 적용한다.
네임스페이스를 삭제한다.
kubectl delete namespace constraints-cpu-example
이 페이지는 네임스페이스에서 실행 중인 모든 파드가 사용할 수 있는 총 메모리 및 CPU 양에 대한 쿼터를 설정하는 방법을 보여준다. 리소스쿼터(ResourceQuota) 오브젝트에 쿼터를 지정할 수 있다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
클러스터에 네임스페이스를 생성할 수 있는 권한이 있어야 한다.
클러스터의 각 노드에는 최소 1GiB의 메모리가 있어야 한다.
이 연습에서 생성한 리소스가 클러스터의 나머지와 격리되도록 네임스페이스를 생성한다.
kubectl create namespace quota-mem-cpu-example
다음은 예시 리소스쿼터 오브젝트에 대한 매니페스트이다.
apiVersion: v1
kind: ResourceQuota
metadata:
name: mem-cpu-demo
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
리소스쿼터를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/quota-mem-cpu.yaml --namespace=quota-mem-cpu-example
리소스쿼터에 대한 자세한 정보를 본다.
kubectl get resourcequota mem-cpu-demo --namespace=quota-mem-cpu-example --output=yaml
리소스쿼터는 이러한 요구 사항을 quota-mem-cpu-example 네임스페이스에 배치한다.
쿠버네티스에서 “1 CPU”가 무엇을 의미하는지 알아보려면 CPU의 의미를 참조한다.
다음은 예시 파드에 대한 매니페스트이다.
apiVersion: v1
kind: Pod
metadata:
name: quota-mem-cpu-demo
spec:
containers:
- name: quota-mem-cpu-demo-ctr
image: nginx
resources:
limits:
memory: "800Mi"
cpu: "800m"
requests:
memory: "600Mi"
cpu: "400m"
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/quota-mem-cpu-pod.yaml --namespace=quota-mem-cpu-example
파드가 실행 중이고 파드의 (유일한) 컨테이너의 상태가 정상인지 확인한다.
kubectl get pod quota-mem-cpu-demo --namespace=quota-mem-cpu-example
다시 한 번, 리소스쿼터에 대한 자세한 정보를 본다.
kubectl get resourcequota mem-cpu-demo --namespace=quota-mem-cpu-example --output=yaml
출력 결과는 쿼터와 사용된 쿼터를 함께 보여준다. 파드의 메모리와 CPU 요청량 및 상한이 쿼터를 초과하지 않은 것을 볼 수 있다.
status:
hard:
limits.cpu: "2"
limits.memory: 2Gi
requests.cpu: "1"
requests.memory: 1Gi
used:
limits.cpu: 800m
limits.memory: 800Mi
requests.cpu: 400m
requests.memory: 600Mi
jq
도구가 설치되어 있으면, (JSONPath를 사용하여) used
값만을 질의 하고,
정돈된 상태로 출력할 수 있다. 예시는 다음과 같다.
kubectl get resourcequota mem-cpu-demo --namespace=quota-mem-cpu-example -o jsonpath='{ .status.used }' | jq .
다음은 두 번째 파드에 대한 매니페스트이다.
apiVersion: v1
kind: Pod
metadata:
name: quota-mem-cpu-demo-2
spec:
containers:
- name: quota-mem-cpu-demo-2-ctr
image: redis
resources:
limits:
memory: "1Gi"
cpu: "800m"
requests:
memory: "700Mi"
cpu: "400m"
매니페스트에서, 파드의 메모리 요청량이 700MiB임을 알 수 있다. 사용된 메모리 요청량과 이 새 메모리 요청량의 합계가 메모리 요청량 쿼터를 초과함에 유의한다(600 MiB + 700 MiB > 1 GiB).
파드 생성을 시도한다.
kubectl apply -f https://k8s.io/examples/admin/resource/quota-mem-cpu-pod-2.yaml --namespace=quota-mem-cpu-example
두 번째 파드는 생성되지 않는다. 출력 결과는 두 번째 파드를 생성하면 메모리 요청량의 총 합계가 메모리 요청량 쿼터를 초과함을 보여준다.
Error from server (Forbidden): error when creating "examples/admin/resource/quota-mem-cpu-pod-2.yaml":
pods "quota-mem-cpu-demo-2" is forbidden: exceeded quota: mem-cpu-demo,
requested: requests.memory=700Mi,used: requests.memory=600Mi, limited: requests.memory=1Gi
이 연습에서 보았듯이, 리소스쿼터를 사용하여 네임스페이스에서 실행 중인 모든 파드에 대한 메모리 요청량의 총 합계를 제한할 수 있다. 메모리 상한, CPU 요청량 및 CPU 상한의 총 합계를 제한할 수도 있다.
네임스페이스 내의 총 자원을 관리하는 것 대신, 개별 파드 또는 파드 내의 컨테이너별로 제한하고 싶을 수도 있다. 이러한 종류의 제한을 걸려면, 리밋레인지(LimitRange)를 사용한다.
네임스페이스를 삭제한다.
kubectl delete namespace quota-mem-cpu-example
이 페이지는 네임스페이스에서 실행할 수 있는 총 파드 수에 대한 쿼터를 설정하는 방법을 보여준다. 리소스쿼터(ResourceQuota) 오브젝트에 쿼터를 지정할 수 있다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
클러스터에 네임스페이스를 생성할 수 있는 권한이 있어야 한다.
이 실습에서 생성한 리소스가 클러스터의 나머지와 격리되도록 네임스페이스를 생성한다.
kubectl create namespace quota-pod-example
다음은 예시 리소스쿼터 오브젝트에 대한 매니페스트이다.
apiVersion: v1
kind: ResourceQuota
metadata:
name: pod-demo
spec:
hard:
pods: "2"
리소스쿼터를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/quota-pod.yaml --namespace=quota-pod-example
리소스쿼터에 대한 자세한 정보를 본다.
kubectl get resourcequota pod-demo --namespace=quota-pod-example --output=yaml
출력 결과는 네임스페이스에 두 개의 파드 쿼터가 있고, 현재 파드가 없음을 보여준다. 즉, 쿼터 중 어느 것도 사용되지 않았다.
spec:
hard:
pods: "2"
status:
hard:
pods: "2"
used:
pods: "0"
다음은 디플로이먼트(Deployment)에 대한 예시 매니페스트이다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-quota-demo
spec:
selector:
matchLabels:
purpose: quota-demo
replicas: 3
template:
metadata:
labels:
purpose: quota-demo
spec:
containers:
- name: pod-quota-demo
image: nginx
매니페스트에서, replicas: 3
은 쿠버네티스가 모두 동일한 애플리케이션을 실행하는
세 개의 새로운 파드를 만들도록 지시한다.
디플로이먼트를 생성한다.
kubectl apply -f https://k8s.io/examples/admin/resource/quota-pod-deployment.yaml --namespace=quota-pod-example
디플로이먼트에 대한 자세한 정보를 본다.
kubectl get deployment pod-quota-demo --namespace=quota-pod-example --output=yaml
출력을 보면 디플로이먼트가 3개의 레플리카를 정의하고 있음에도, 앞서 설정한 쿼터로 인해 2개의 파드만 생성되었음을 보여준다.
spec:
...
replicas: 3
...
status:
availableReplicas: 2
...
lastUpdateTime: 2021-04-02T20:57:05Z
message: 'unable to create pods: pods "pod-quota-demo-1650323038-" is forbidden:
exceeded quota: pod-demo, requested: pods=1, used: pods=2, limited: pods=2'
이 예제에서는 총 파드 수를 제한하는 리소스쿼터를 정의하였다. 하지만, 다른 종류의 오브젝트의 총 수를 제한할 수도 있다. 예를 들어, 한 네임스페이스에 존재할 수 있는 크론잡의 총 수를 제한할 수 있다.
네임스페이스를 삭제한다.
kubectl delete namespace quota-pod-example
클라이언트 인증서로 인증을 사용하는 경우 easyrsa
, openssl
또는 cfssl
을 통해 인증서를 수동으로 생성할 수 있다.
easyrsa 는 클러스터 인증서를 수동으로 생성할 수 있다.
easyrsa3의 패치 버전을 다운로드하여 압축을 풀고, 초기화한다.
curl -LO https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz
tar xzf easy-rsa.tar.gz
cd easy-rsa-master/easyrsa3
./easyrsa init-pki
새로운 인증 기관(CA)을 생성한다. --batch
는 자동 모드를 설정한다.
--req-cn
는 CA의 새 루트 인증서에 대한 일반 이름(Common Name (CN))을 지정한다.
./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass
서버 인증서와 키를 생성한다.
--subject-alt-name
인수는 API 서버에 접근이 가능한 IP와 DNS
이름을 설정한다. MASTER_CLUSTER_IP
는 일반적으로 API 서버와
컨트롤러 관리자 컴포넌트에 대해 --service-cluster-ip-range
인수로
지정된 서비스 CIDR의 첫 번째 IP이다. --days
인수는 인증서가 만료되는
일 수를 설정하는데 사용된다.
또한, 아래 샘플은 기본 DNS 이름으로 cluster.local
을
사용한다고 가정한다.
./easyrsa --subject-alt-name="IP:${MASTER_IP},"\
"IP:${MASTER_CLUSTER_IP},"\
"DNS:kubernetes,"\
"DNS:kubernetes.default,"\
"DNS:kubernetes.default.svc,"\
"DNS:kubernetes.default.svc.cluster,"\
"DNS:kubernetes.default.svc.cluster.local" \
--days=10000 \
build-server-full server nopass
pki/ca.crt
, pki/issued/server.crt
그리고 pki/private/server.key
를 디렉터리에 복사한다.
API 서버 시작 파라미터에 다음 파라미터를 채우고 추가한다.
--client-ca-file=/yourdirectory/ca.crt
--tls-cert-file=/yourdirectory/server.crt
--tls-private-key-file=/yourdirectory/server.key
openssl 은 클러스터 인증서를 수동으로 생성할 수 있다.
ca.key를 2048bit로 생성한다.
openssl genrsa -out ca.key 2048
ca.key에 따라 ca.crt를 생성한다(인증서 유효 기간을 사용하려면 -days를 사용한다).
openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt
server.key를 2048bit로 생성한다.
openssl genrsa -out server.key 2048
인증서 서명 요청(Certificate Signing Request (CSR))을 생성하기 위한 설정 파일을 생성한다.
파일에 저장하기 전에 꺾쇠 괄호(예: <MASTER_IP>
)로
표시된 값을 실제 값으로 대체한다(예: csr.conf
).
MASTER_CLUSTER_IP
의 값은 이전 하위 섹션에서
설명한 대로 API 서버의 서비스 클러스터 IP이다.
또한, 아래 샘플에서는 cluster.local
을 기본 DNS 도메인
이름으로 사용하고 있다고 가정한다.
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[ dn ]
C = <국가(country)>
ST = <도(state)>
L = <시(city)>
O = <조직(organization)>
OU = <조직 단위(organization unit)>
CN = <MASTER_IP>
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
IP.1 = <MASTER_IP>
IP.2 = <MASTER_CLUSTER_IP>
[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=@alt_names
설정 파일을 기반으로 인증서 서명 요청을 생성한다.
openssl req -new -key server.key -out server.csr -config csr.conf
ca.key, ca.crt 그리고 server.csr을 사용해서 서버 인증서를 생성한다.
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt -days 10000 \
-extensions v3_ext -extfile csr.conf
인증서 서명 요청을 확인한다.
openssl req -noout -text -in ./server.csr
인증서를 확인한다.
openssl x509 -noout -text -in ./server.crt
마지막으로, API 서버 시작 파라미터에 동일한 파라미터를 추가한다.
cfssl 은 인증서 생성을 위한 또 다른 도구이다.
아래에 표시된 대로 커맨드 라인 도구를 다운로드하여 압축을 풀고 준비한다. 사용 중인 하드웨어 아키텍처 및 cfssl 버전에 따라 샘플 명령을 조정해야 할 수도 있다.
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.5.0/cfssl_1.5.0_linux_amd64 -o cfssl
chmod +x cfssl
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.5.0/cfssljson_1.5.0_linux_amd64 -o cfssljson
chmod +x cfssljson
curl -L https://github.com/cloudflare/cfssl/releases/download/v1.5.0/cfssl-certinfo_1.5.0_linux_amd64 -o cfssl-certinfo
chmod +x cfssl-certinfo
아티팩트(artifact)를 보유할 디렉터리를 생성하고 cfssl을 초기화한다.
mkdir cert
cd cert
../cfssl print-defaults config > config.json
../cfssl print-defaults csr > csr.json
CA 파일을 생성하기 위한 JSON 설정 파일을 ca-config.json
예시와 같이 생성한다.
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "8760h"
}
}
}
}
CA 인증서 서명 요청(CSR)을 위한 JSON 설정 파일을
ca-csr.json
예시와 같이 생성한다. 꺾쇠 괄호로 표시된
값을 사용하려는 실제 값으로 변경한다.
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names":[{
"C": "<국가(country)>",
"ST": "<도(state)>",
"L": "<시(city)>",
"O": "<조직(organization)>",
"OU": "<조직 단위(organization unit)>"
}]
}
CA 키(ca-key.pem
)와 인증서(ca.pem
)을 생성한다.
../cfssl gencert -initca ca-csr.json | ../cfssljson -bare ca
API 서버의 키와 인증서를 생성하기 위한 JSON 구성파일을
server-csr.json
예시와 같이 생성한다. 꺾쇠 괄호 안의 값을
사용하려는 실제 값으로 변경한다. MASTER_CLUSTER_IP
는
이전 하위 섹션에서 설명한 API 서버의 클러스터 IP이다.
아래 샘플은 기본 DNS 도메인 이름으로 cluster.local
을
사용한다고 가정한다.
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"<MASTER_IP>",
"<MASTER_CLUSTER_IP>",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [{
"C": "<국가(country)>",
"ST": "<도(state)>",
"L": "<시(city)>",
"O": "<조직(organization)>",
"OU": "<조직 단위(organization unit)>"
}]
}
API 서버 키와 인증서를 생성하면, 기본적으로
server-key.pem
과 server.pem
파일에 각각 저장된다.
../cfssl gencert -ca=ca.pem -ca-key=ca-key.pem \
--config=ca-config.json -profile=kubernetes \
server-csr.json | ../cfssljson -bare server
클라이언트 노드는 자체 서명된 CA 인증서를 유효한 것으로 인식하지 않을 수 있다. 비-프로덕션 디플로이먼트 또는 회사 방화벽 뒤에서 실행되는 디플로이먼트의 경우, 자체 서명된 CA 인증서를 모든 클라이언트에 배포하고 유효한 인증서의 로컬 목록을 새로 고칠 수 있다.
각 클라이언트에서, 다음 작업을 수행한다.
sudo cp ca.crt /usr/local/share/ca-certificates/kubernetes.crt
sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....
done.
certificates.k8s.io
API를 사용해서
여기에
설명된 대로 인증에 사용할 x509 인증서를 프로비전 할 수 있다.
이 페이지는 쿠버네티스에서 캘리코(Calico) 클러스터를 생성하는 몇 가지 빠른 방법을 살펴본다.
클라우드나 지역 클러스터 중에 어디에 배포할지 결정한다.
사전요구사항: gcloud.
캘리코로 GKE 클러스터를 시작하려면, --enable-network-policy
플래그를 추가한다.
문법
gcloud container clusters create [클러스터_이름] --enable-network-policy
예시
gcloud container clusters create my-calico-cluster --enable-network-policy
배포를 확인하기 위해, 다음 커맨드를 이용하자.
kubectl get pods --namespace=kube-system
캘리코 파드는 calico
로 시작한다. 각각의 상태가 Running
임을 확인하자.
Kubeadm을 이용해서 15분 이내에 지역 단일 호스트 캘리코 클러스터를 생성하려면, 캘리코 빠른 시작을 참고한다.
클러스터가 동작하면, 쿠버네티스 네트워크 폴리시(NetworkPolicy)를 시도하기 위해 네트워크 폴리시 선언하기를 따라 할 수 있다.
이 페이지는 어떻게 네트워크 폴리시(NetworkPolicy)로 실리움(Cilium)를 사용하는지 살펴본다.
실리움의 배경에 대해서는 실리움 소개를 읽어보자.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.실리움에 쉽게 친숙해지기 위해 Minikube에 실리움을 기본적인 데몬셋으로 설치를 수행하는 실리움 쿠버네티스 시작하기 안내를 따라 해볼 수 있다.
Minikube를 시작하려면 최소 버전으로 >= v1.5.2 이 필요하고, 다음의 실행 파라미터로 실행한다.
minikube version
minikube version: v1.5.2
minikube start --network-plugin=cni
minikube의 경우 CLI 도구를 사용하여 실리움을 설치할 수 있다. 실리움은 클러스터 구성을 자동으로 감지하고 성공적인 설치를 위해 적절한 구성 요소를 설치한다.
curl -LO https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz
sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
rm cilium-linux-amd64.tar.gz
cilium install
🔮 Auto-detected Kubernetes kind: minikube
✨ Running "minikube" validation checks
✅ Detected minikube version "1.20.0"
ℹ️ Cilium version not set, using default version "v1.10.0"
🔮 Auto-detected cluster name: minikube
🔮 Auto-detected IPAM mode: cluster-pool
🔮 Auto-detected datapath mode: tunnel
🔑 Generating CA...
2021/05/27 02:54:44 [INFO] generate received request
2021/05/27 02:54:44 [INFO] received CSR
2021/05/27 02:54:44 [INFO] generating key: ecdsa-256
2021/05/27 02:54:44 [INFO] encoded CSR
2021/05/27 02:54:44 [INFO] signed certificate with serial number 48713764918856674401136471229482703021230538642
🔑 Generating certificates for Hubble...
2021/05/27 02:54:44 [INFO] generate received request
2021/05/27 02:54:44 [INFO] received CSR
2021/05/27 02:54:44 [INFO] generating key: ecdsa-256
2021/05/27 02:54:44 [INFO] encoded CSR
2021/05/27 02:54:44 [INFO] signed certificate with serial number 3514109734025784310086389188421560613333279574
🚀 Creating Service accounts...
🚀 Creating Cluster roles...
🚀 Creating ConfigMap...
🚀 Creating Agent DaemonSet...
🚀 Creating Operator Deployment...
⌛ Waiting for Cilium to be installed...
시작하기 안내서의 나머지 부분은 예제 애플리케이션을 이용하여 L3/L4(예, IP 주소 + 포트) 모두의 보안 정책뿐만 아니라 L7(예, HTTP)의 보안 정책을 적용하는 방법을 설명한다.
실리움을 실 서비스 용도의 배포에 관련한 자세한 방법은 실리움 쿠버네티스 설치 안내를 살펴본다. 이 문서는 자세한 요구사항, 방법과 실제 데몬셋 예시를 포함한다.
실리움으로 클러스터를 배포하면 파드가 kube-system
네임스페이스에 추가된다.
파드의 목록을 보려면 다음을 실행한다.
kubectl get pods --namespace=kube-system -l k8s-app=cilium
다음과 유사한 파드의 목록을 볼 것이다.
NAME READY STATUS RESTARTS AGE
cilium-kkdhz 1/1 Running 0 3m23s
...
cilium
파드는 클러스터 각 노드에서 실행되며, 리눅스 BPF를 사용해서
해당 노드의 파드에 대한 트래픽 네트워크 폴리시를 적용한다.
클러스터가 동작하면, 실리움으로 쿠버네티스 네트워크 폴리시를 시도하기 위해 네트워크 폴리시 선언하기를 따라 할 수 있다. 재미있게 즐기고, 질문이 있다면 실리움 슬랙 채널을 이용하여 연락한다.
이 페이지는 네트워크 폴리시(NetworkPolicy)로 큐브 라우터(Kube-router)를 사용하는 방법을 살펴본다.
운영 중인 쿠버네티스 클러스터가 필요하다. 클러스터가 없다면, Kops, Bootkube, Kubeadm 등을 이용해서 클러스터를 생성할 수 있다.
큐브 라우터 애드온은 갱신된 모든 네트워크 폴리시 및 파드에 대해 쿠버네티스 API 서버를 감시하고, 정책에 따라 트래픽을 허용하거나 차단하도록 iptables 규칙와 ipset을 구성하는 네트워크 폴리시 컨트롤러와 함께 제공된다. 큐브 라우터 애드온을 설치하는 큐브 라우터를 클러스터 인스톨러와 함께 사용하기 안내서를 따라해 봅니다.
큐브 라우터 애드온을 설치한 후에는, 쿠버네티스 네트워크 폴리시를 시도하기 위해 네트워크 폴리시 선언하기를 따라 할 수 있다.
이 페이지는 네트워크 폴리시(NetworkPolicy)로 로마나(Romana)를 사용하는 방법을 살펴본다.
kubeadm 시작하기의 1, 2, 3 단계를 완료하자.
Kubeadm을 위한 컨테이너화된 설치 안내서를 따른다.
네트워크 폴리시를 적용하기 위해 다음 중에 하나를 사용하자.
로마나를 설치한 후에는, 쿠버네티스 네트워크 폴리시를 시도하기 위해 네트워크 폴리시 선언하기를 따라 할 수 있다.
이 페이지는 네트워크 폴리시(NetworkPolicy)로 위브넷(Weave Net)를 사용하는 방법을 살펴본다.
쿠버네티스 클러스터가 필요하다. 맨 땅에서부터 시작하기를 위해서 kubeadm 시작하기 안내서를 따른다.
애드온을 통한 쿠버네티스 통합하기 가이드를 따른다.
쿠버네티스의 위브넷 애드온은 쿠버네티스의 모든 네임스페이스의
네크워크 정책 어노테이션을 자동으로 모니터링하며,
정책에 따라 트래픽을 허용하고 차단하는 iptables
규칙을 구성하는
네트워크 폴리시 컨트롤러와 함께 제공된다.
위브넷이 동작하는지 확인한다.
다음 커맨드를 입력한다.
kubectl get pods -n kube-system -o wide
출력은 다음과 유사하다.
NAME READY STATUS RESTARTS AGE IP NODE
weave-net-1t1qg 2/2 Running 0 9d 192.168.2.10 worknode3
weave-net-231d7 2/2 Running 1 7d 10.2.0.17 worknodegpu
weave-net-7nmwt 2/2 Running 3 9d 192.168.2.131 masternode
weave-net-pmw8w 2/2 Running 0 9d 192.168.2.216 worknode2
위브넷 파드를 가진 각 노드와 모든 파드는 Running
이고 2/2 READY
이다(2/2
는 각 파드가 weave
와 weave-npc
를 가지고 있음을 뜻한다).
위브넷 애드온을 설치하고 나서, 쿠버네티스 네트워크 폴리시를 시도하기 위해 네트워크 폴리시 선언하기를 따라 할 수 있다. 질문이 있으면 슬랙 #weave-community 이나 Weave 유저그룹에 연락한다.
이 페이지는 클러스터 안에서 사용자의 DNS 파드(Pod) 를 설정하고 DNS 변환(DNS resolution) 절차를 사용자 정의하는 방법을 설명한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
클러스터는 CoreDNS 애드온을 구동하고 있어야 한다.
CoreDNS로 이관하기
는 kubeadm
을 이용하여 kube-dns
로부터 이관하는 방법을 설명한다.
쿠버네티스 서버의 버전은 다음과 같거나 더 높아야 함. 버전: v1.12.
버전 확인을 위해서, 다음 커맨드를 실행 kubectl version
.
DNS는 애드온 관리자 인 클러스터 애드온을 사용하여 자동으로 시작되는 쿠버네티스 내장 서비스이다.
쿠버네티스 v1.12 부터, CoreDNS는 kube-dns를 대체하여 권장되는 DNS 서버이다. 만약 사용자의 클러스터가 원래 kube-dns를 사용하였을 경우,
CoreDNS 대신 kube-dns
를 계속 사용할 수도 있다.
metadata.name
필드에 kube-dns
로 이름이 지정된다.
이를 통해, 기존의 kube-dns
서비스 이름을 사용하여 클러스터 내부의 주소를 확인하는 워크로드에 대한 상호 운용성이 증가된다. kube-dns
로 서비스 이름을 사용하면, 해당 DNS 공급자가 어떤 공통 이름으로 실행되고 있는지에 대한 구현 세부 정보를 추상화한다.CoreDNS를 디플로이먼트(Deployment)로 실행하고 있을 경우, 일반적으로 고정 IP 주소를 갖는 쿠버네티스 서비스로 노출된다.
Kubelet 은 --cluster-dns=<dns-service-ip>
플래그를 사용하여 DNS 확인자 정보를 각 컨테이너에 전달한다.
DNS 이름에도 도메인이 필요하다. 사용자는 kubelet 에 있는 --cluster-domain=<default-local-domain>
플래그를
통하여 로컬 도메인을 설정할 수 있다.
DNS 서버는 정방향 조회(A 및 AAAA 레코드), 포트 조회(SRV 레코드), 역방향 IP 주소 조회(PTR 레코드) 등을 지원한다. 더 자세한 내용은 서비스 및 파드용 DNS를 참고한다.
만약 파드의 dnsPolicy
가 default
로 지정되어 있는 경우,
파드는 자신이 실행되는 노드의 이름 변환(name resolution) 구성을 상속한다.
파드의 DNS 변환도 노드와 동일하게 작동해야 한다.
그 외에는 알려진 이슈를 참고한다.
만약 위와 같은 방식을 원하지 않거나, 파드를 위해 다른 DNS 설정이 필요한 경우,
사용자는 kubelet 의 --resolv-conf
플래그를 사용할 수 있다.
파드가 DNS를 상속받지 못하도록 하기 위해 이 플래그를 ""로 설정한다.
DNS 상속을 위해 /etc/resolv.conf
이외의 파일을 지정할 경우 유효한 파일 경로를 설정한다.
CoreDNS는 dns 명세를 준수하며 클러스터 DNS 역할을 할 수 있는, 범용적인 권한을 갖는 DNS 서버이다.
CoreDNS는 모듈형이자 플러그인이 가능한 DNS 서버이며, 각 플러그인들은 CoreDNS에 새로운 기능을 부가한다. 이는 CoreDNS 구성 파일인 Corefile을 관리하여 구성할 수 있다. 클러스터 관리자는 CoreDNS Corefile에 대한 컨피그맵을 수정하여 해당 클러스터에 대한 DNS 서비스 검색 동작을 변경할 수 있다.
쿠버네티스에서 CoreDNS는 아래의 기본 Corefile 구성으로 설치된다.
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
Corefile의 구성은 CoreDNS의 아래 플러그인을 포함한다.
http://localhost:8080/health
에 기록된다. 이 확장 구문에서 lameduck
은 프로세스를 비정상 상태(unhealthy)로 만들고, 프로세스가 종료되기 전에 5초 동안 기다린다.ttl
을 사용하면 응답에 대한 사용자 정의 TTL 을 지정할 수 있으며, 기본값은 5초이다. 허용되는 최소 TTL은 0초이며, 최대값은 3600초이다. 레코드가 캐싱되지 않도록 할 경우, TTL을 0으로 설정한다.
pods insecure
옵션은 kube-dns 와의 하위 호환성을 위해 제공된다. pods verified
옵션을 사용하여, 일치하는 IP의 동일 네임스페이스(Namespace)에 파드가 존재하는 경우에만 A 레코드를 반환하게 할 수 있다. pods disabled
옵션은 파드 레코드를 사용하지 않을 경우 사용된다.http://localhost:9153/metrics
에서 사용 가능하다.사용자는 컨피그맵을 변경하여 기본 CoreDNS 동작을 변경할 수 있다.
CoreDNS는 포워드 플러그인을 사용하여 스텁 도메인 및 업스트림 네임서버를 구성할 수 있다.
만약 클러스터 운영자가 10.150.0.1 에 위치한 Consul 도메인 서버를 가지고 있고, 모든 Consul 이름의 접미사가 .consul.local 인 경우, CoreDNS에서 이를 구성하기 위해 클러스터 관리자는 CoreDNS 컨피그맵에서 다음 구문을 생성한다.
consul.local:53 {
errors
cache 30
forward . 10.150.0.1
}
모든 비 클러스터의 DNS 조회가 172.16.0.1 의 특정 네임서버를 통과하도록 할 경우, /etc/resolv.conf
대신 forward
를 네임서버로 지정한다.
forward . 172.16.0.1
기본 Corefile
구성에 따른 최종 컨피그맵은 다음과 같다.
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . 172.16.0.1
cache 30
loop
reload
loadbalance
}
consul.local:53 {
errors
cache 30
forward . 10.150.0.1
}
Kubeadm
툴은 kube-dns 컨피그맵에서 동일한 설정의 CoreDNS 컨피그맵으로의
자동 변환을 지원한다.
CoreDNS는 kube-dns 이상의 기능을 지원한다.
StubDomains
과 upstreamNameservers
를 지원하도록 생성된 kube-dns의 컨피그맵은 CoreDNS의 forward
플러그인으로 변환된다.
kube-dns에 대한 이 컨피그맵 예제는 stubDomains 및 upstreamNameservers를 지정한다.
apiVersion: v1
data:
stubDomains: |
{"abc.com" : ["1.2.3.4"], "my.cluster.local" : ["2.3.4.5"]}
upstreamNameservers: |
["8.8.8.8", "8.8.4.4"]
kind: ConfigMap
CoreDNS에서는 동등한 설정으로 Corefile을 생성한다.
abc.com:53 {
errors
cache 30
forward . 1.2.3.4
}
my.cluster.local:53 {
errors
cache 30
forward . 2.3.4.5
}
기본 플러그인으로 구성된 완전한 Corefile.
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
federation cluster.local {
foo foo.feddomain.com
}
prometheus :9153
forward . 8.8.8.8 8.8.4.4
cache 30
}
abc.com:53 {
errors
cache 30
forward . 1.2.3.4
}
my.cluster.local:53 {
errors
cache 30
forward . 2.3.4.5
}
kube-dns에서 CoreDNS로 이관하기 위하여, kube-dns를 CoreDNS로 교체하여 적용하는 방법에 대한 상세 정보는 블로그 기사를 참고한다.
또한 공식적인 CoreDNS 배포 스크립트를 사용하여 이관할 수도 있다.
이 페이지는 특별한 요구사항이 없는 퍼시스턴트볼륨클레임(PersistentVolumeClaim)의 볼륨을 프로비저닝 하는데 사용되는 기본 스토리지 클래스를 변경하는 방법을 보여준다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.설치 방법에 따라, 사용자의 쿠버네티스 클러스터는 기본으로 표시된 기존 스토리지클래스와 함께 배포될 수 있다. 이 기본 스토리지클래스는 특정 스토리지 클래스가 필요하지 않은 퍼시스턴트볼륨클레임에 대해 스토리지를 동적으로 프로비저닝 하기 위해 사용된다. 더 자세한 내용은 퍼시스턴트볼륨클레임 문서를 보자.
미리 설치된 기본 스토리지클래스가 사용자의 예상되는 워크로드에 적합하지 않을수도 있다. 예를 들어, 너무 가격이 높은 스토리지를 프로비저닝 해야할 수도 있다. 이런 경우에, 기본 스토리지 클래스를 변경하거나 완전히 비활성화 하여 스토리지의 동적 프로비저닝을 방지할 수 있다.
기본 스토리지클래스를 삭제하는 경우, 사용자의 클러스터에서 구동 중인 애드온 매니저에 의해 자동으로 다시 생성될 수 있으므로 정상적으로 삭제가 되지 않을 수도 있다. 애드온 관리자 및 개별 애드온을 비활성화 하는 방법에 대한 자세한 내용은 설치 문서를 참조하자.
사용자의 클러스터에 있는 스토리지클래스 목록을 조회한다.
kubectl get storageclass
결과는 아래와 유사하다.
NAME PROVISIONER AGE
standard (default) kubernetes.io/gce-pd 1d
gold kubernetes.io/gce-pd 1d
기본 스토리지클래스는 (default)
로 표시되어 있다.
기본 스토리지클래스를 기본값이 아닌 것으로 표시한다.
기본 스토리지클래스에는
storageclass.kubernetes.io/is-default-class
의 값이 true
로 설정되어 있다.
다른 값이거나 어노테이션이 없을 경우 false
로 처리된다.
스토리지클래스를 기본값이 아닌 것으로 표시하려면, 그 값을 false
로 변경해야 한다.
kubectl patch storageclass standard -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
여기서 standard
는 사용자가 선택한 스토리지클래스의 이름이다.
스토리지클래스를 기본값으로 표시한다.
이전 과정과 유사하게, 어노테이션을 추가/설정해야 한다.
storageclass.kubernetes.io/is-default-class=true
.
kubectl patch storageclass gold -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
최대 1개의 스토리지클래스를 기본값으로 표시할 수 있다는 것을 알아두자. 만약
2개 이상이 기본값으로 표시되면, 명시적으로 storageClassName
가 지정되지 않은 PersistentVolumeClaim
은 생성될 수 없다.
사용자가 선택한 스토리지클래스가 기본값으로 되어 있는지 확인한다.
kubectl get storageclass
결과는 아래와 유사하다.
NAME PROVISIONER AGE
standard kubernetes.io/gce-pd 1d
gold (default) kubernetes.io/gce-pd 1d
이 문서는 사용자가 쿠버네티스 네트워크폴리시 API를 사용하여 파드(Pod)가 서로 통신하는 방법을 제어하는 네트워크 폴리시를 선언하는데 도움을 준다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
쿠버네티스 서버의 버전은 다음과 같거나 더 높아야 함. 버전: v1.8. 버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.네트워크 폴리시를 지원하는 네트워크 제공자를 구성하였는지 확인해야 한다. 다음과 같이 네트워크폴리시를 지원하는 많은 네트워크 제공자들이 있다.
nginx
디플로이먼트(Deployment)를 생성하고 서비스(Service)를 통해 노출하기쿠버네티스 네트워크 폴리시가 어떻게 동작하는지 확인하기 위해서, nginx
디플로이먼트를 생성한다.
kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
nginx
라는 이름의 서비스를 통해 디플로이먼트를 노출한다.
kubectl expose deployment nginx --port=80
service/nginx exposed
위 명령어들은 nginx 파드에 대한 디플로이먼트를 생성하고, nginx
라는 이름의 서비스를 통해 디플로이먼트를 노출한다. nginx
파드와 디플로이먼트는 default
네임스페이스(namespace)에 존재한다.
kubectl get svc,pod
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes 10.100.0.1 <none> 443/TCP 46m
service/nginx 10.100.0.16 <none> 80/TCP 33s
NAME READY STATUS RESTARTS AGE
pod/nginx-701339712-e0qfq 1/1 Running 0 35s
사용자는 다른 파드에서 새 nginx
서비스에 접근할 수 있어야 한다. default
네임스페이스에 있는 다른 파드에서 nginx
서비스에 접근하기 위하여, busybox 컨테이너를 생성한다.
kubectl run busybox --rm -ti --image=busybox -- /bin/sh
사용자 쉘에서, 다음의 명령을 실행한다.
wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
remote file exists
nginx
서비스에 대해 접근 제한하기access: true
레이블을 가지고 있는 파드만 nginx
서비스에 접근할 수 있도록 하기 위하여, 다음과 같은 네트워크폴리시 오브젝트를 생성한다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
app: nginx
ingress:
- from:
- podSelector:
matchLabels:
access: "true"
네트워크폴리시 오브젝트의 이름은 유효한 DNS 서브도메인 이름이어야 한다.
podSelector
를 포함한다. 사용자는 이 정책이 app=nginx
레이블을 갖는 파드를 선택하는 것을 볼 수 있다. 레이블은 nginx
디플로이먼트에 있는 파드에 자동으로 추가된다. 빈 podSelector
는 네임스페이스의 모든 파드를 선택한다.kubectl을 사용하여 위 nginx-policy.yaml
파일로부터 네트워크폴리시를 생성한다.
kubectl apply -f https://k8s.io/examples/service/networking/nginx-policy.yaml
networkpolicy.networking.k8s.io/access-nginx created
올바른 레이블이 없는 파드에서 nginx
서비스에 접근하려 할 경우, 요청 타임 아웃이 발생한다.
kubectl run busybox --rm -ti --image=busybox -- /bin/sh
사용자 쉘에서, 다음의 명령을 실행한다.
wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
wget: download timed out
사용자는 요청이 허용되도록 하기 위하여 올바른 레이블을 갖는 파드를 생성한다.
kubectl run busybox --rm -ti --labels="access=true" --image=busybox -- /bin/sh
사용자 쉘에서, 다음의 명령을 실행한다.
wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
remote file exists
이 페이지는 노드의 확장 리소스를 지정하는 방법을 보여준다. 확장 리소스를 통해 클러스터 관리자는 쿠버네티스에게 알려지지 않은 노드-레벨 리소스를 알릴 수 있다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.kubectl get nodes
이 연습에 사용할 노드 중 하나를 선택한다.
노드에서 새로운 확장 리소스를 알리려면, 쿠버네티스 API 서버에 HTTP PATCH 요청을 보낸다. 예를 들어, 노드 중 하나에 4개의 동글(dongle)이 있다고 가정한다. 다음은 노드에 4개의 동글 리소스를 알리는 PATCH 요청의 예이다.
PATCH /api/v1/nodes/<your-node-name>/status HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
Host: k8s-master:8080
[
{
"op": "add",
"path": "/status/capacity/example.com~1dongle",
"value": "4"
}
]
참고로 쿠버네티스는 동글이 무엇인지 또는 동글이 무엇을 위한 것인지 알 필요가 없다. 위의 PATCH 요청은 노드에 동글이라고 하는 네 가지 항목이 있음을 쿠버네티스에 알려준다.
쿠버네티스 API 서버에 요청을 쉽게 보낼 수 있도록 프록시를 시작한다.
kubectl proxy
다른 명령 창에서 HTTP PATCH 요청을 보낸다.
<your-node-name>
을 노드의 이름으로 바꾼다.
curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "add", "path": "/status/capacity/example.com~1dongle", "value": "4"}]' \
http://localhost:8001/api/v1/nodes/<your-node-name>/status
~1
은 패치 경로의 / 문자에 대한
인코딩이다. JSON-Patch의 작업 경로값은 JSON-Pointer로
해석된다. 자세한 내용은 IETF RFC 6901의
섹션 3을 참고한다.출력은 노드가 4개의 동글 용량을 가졌음을 나타낸다.
"capacity": {
"cpu": "2",
"memory": "2049008Ki",
"example.com/dongle": "4",
노드의 정보를 확인한다.
kubectl describe node <your-node-name>
다시 한 번, 출력에 동글 리소스가 표시된다.
Capacity:
cpu: 2
memory: 2049008Ki
example.com/dongle: 4
이제, 애플리케이션 개발자는 특정 개수의 동글을 요청하는 파드를 만들 수 있다. 컨테이너에 확장 리소스 할당하기를 참고한다.
확장 리소스는 메모리 및 CPU 리소스와 비슷하다. 예를 들어, 노드에서 실행 중인 모든 컴포넌트가 공유할 특정 양의 메모리와 CPU가 노드에 있는 것처럼, 노드에서 실행 중인 모든 컴포넌트가 특정 동글을 공유할 수 있다. 또한 애플리케이션 개발자가 특정 양의 메모리와 CPU를 요청하는 파드를 생성할 수 있는 것처럼, 특정 동글을 요청하는 파드를 생성할 수 있다.
확장 리소스는 쿠버네티스에게 불투명하다. 쿠버네티스는 그것들이 무엇인지 전혀 모른다. 쿠버네티스는 노드에 특정 개수의 노드만 있다는 것을 알고 있다. 확장 리소스는 정수로 알려야 한다. 예를 들어, 노드는 4.5개의 동글이 아닌, 4개의 동글을 알릴 수 있다.
노드에 800GiB의 특별한 종류의 디스크 스토리지가 있다고 가정한다. example.com/special-storage와 같은 특별한 스토리지의 이름을 생성할 수 있다. 그런 다음 특정 크기, 100GiB의 청크로 알릴 수 있다. 이 경우, 노드에는 example.com/special-storage 유형의 8가지 리소스가 있다고 알린다.
Capacity:
...
example.com/special-storage: 8
이 특별한 스토리지에 대한 임의 요청을 허용하려면, 1바이트 크기의 청크로 특별한 스토리지를 알릴 수 있다. 이 경우, example.com/special-storage 유형의 800Gi 리소스를 알린다.
Capacity:
...
example.com/special-storage: 800Gi
그런 다음 컨테이너는 최대 800Gi의 임의 바이트 수의 특별한 스토리지를 요청할 수 있다.
다음은 노드에서 동글 알림을 제거하는 PATCH 요청이다.
PATCH /api/v1/nodes/<your-node-name>/status HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
Host: k8s-master:8080
[
{
"op": "remove",
"path": "/status/capacity/example.com~1dongle",
}
]
쿠버네티스 API 서버에 요청을 쉽게 보낼 수 있도록 프록시를 시작한다.
kubectl proxy
다른 명령 창에서 HTTP PATCH 요청을 보낸다.
<your-node-name>
을 노드의 이름으로 바꾼다.
curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "remove", "path": "/status/capacity/example.com~1dongle"}]' \
http://localhost:8001/api/v1/nodes/<your-node-name>/status
동글 알림이 제거되었는지 확인한다.
kubectl describe node <your-node-name> | grep dongle
(출력이 보이지 않아야 함)
이 페이지는 CoreDNS 업그레이드 프로세스와 kube-dns 대신 CoreDNS를 설치하는 방법을 보여준다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
쿠버네티스 서버의 버전은 다음과 같거나 더 높아야 함. 버전: v1.9. 버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.CoreDNS는 쿠버네티스 클러스터의 DNS 역할을 수행할 수 있는, 유연하고 확장 가능한 DNS 서버이다. 쿠버네티스와 동일하게, CoreDNS 프로젝트도 CNCF가 관리한다.
사용자는 기존 디플로이먼트인 kube-dns를 교체하거나, 클러스터를 배포하고 업그레이드하는 kubeadm과 같은 툴을 사용하여 클러스터 안의 kube-dns 대신 CoreDNS를 사용할 수 있다.
Kube-dns의 배포나 교체에 관한 매뉴얼은 CoreDNS GitHub 프로젝트에 있는 문서를 확인하자.
쿠버네티스 버전 1.10 이상에서, kube-dns
를 사용하는 클러스터를 업그레이드하기 위하여
kubeadm
을 사용할 때 CoreDNS로 전환할 수도 있다. 이 경우, kubeadm
은
kube-dns
컨피그맵(ConfigMap)을 기반으로 스텁 도메인(stub domain), 업스트림 네임 서버의
설정을 유지하며 CoreDNS 설정("Corefile")을 생성한다.
만약 kube-dns에서 CoreDNS로 이동하는 경우, 업그레이드 과정에서 기능 게이트의 CoreDNS
값을 true
로 설정해야 한다.
예를 들어, v1.11.0
로 업그레이드 하는 경우는 다음과 같다.
kubeadm upgrade apply v1.11.0 --feature-gates=CoreDNS=true
쿠버네티스 1.13 이상에서 기능 게이트의 CoreDNS
항목은 제거되었으며, CoreDNS가 기본적으로 사용된다.
1.11 미만 버전일 경우 업그레이드 과정에서 만들어진 파일이 Corefile을 덮어쓴다. 만약 컨피그맵을 사용자 정의한 경우, 기존의 컨피그맵을 저장해야 한다. 새 컨피그맵이 시작된 후에 변경 사항을 다시 적용해야 할 수도 있다.
만약 쿠버네티스 1.11 이상 버전에서 CoreDNS를 사용하는 경우, 업그레이드 과정에서, 기존의 Corefile이 유지된다.
쿠버네티스 버전 1.21에서, kubeadm 의 kube-dns
지원 기능이 삭제되었다.
CoreDNS는 쿠버네티스 1.9 버전부터 사용할 수 있다. 쿠버네티스와 함께 제공되는 CoreDNS의 버전과 CoreDNS의 변경 사항은 여기에서 확인할 수 있다.
CoreDNS는 사용자 정의 이미지를 사용하거나 CoreDNS만 업그레이드 하려는 경우에 수동으로 업그레이드할 수 있다. 업그레이드를 원활하게 수행하는 데 유용한 가이드라인 및 연습을 참고하자.
리소스 활용이 중요한 경우, CoreDNS 구성을 조정하는 것이 유용할 수 있다. 더 자세한 내용은 CoreDNS 스케일링에 대한 설명서를 확인하자.
Corefile
을 수정하여 kube-dns 보다 더 많은 유스케이스를 지원하도록
CoreDNS를 구성할 수 있다.
더 자세한 내용은 CoreDNS 웹사이트을 확인하자.
API 서버, 스케줄러 및 컨트롤러 매니저와 같은 쿠버네티스 주요 컴포넌트들은 컨트롤 플레인 노드에서 동작한다. 반면, 애드온들은 일반 클러스터 노드에서 동작한다. 이러한 애드온들 중 일부(예: 메트릭 서버, DNS, UI)는 클러스터 전부가 정상적으로 동작하는 데 필수적일 수 있다. 만약, 필수 애드온이 축출되고(수동 축출, 혹은 업그레이드와 같은 동작으로 인한 의도하지 않은 축출) pending 상태가 된다면, 클러스터가 더 이상 제대로 동작하지 않을 수 있다. (사용률이 매우 높은 클러스터에서 해당 애드온이 축출되자마자 다른 대기중인 파드가 스케줄링되거나 다른 이유로 노드에서 사용할 수 있는 자원량이 줄어들어 pending 상태가 발생할 수 있다)
유의할 점은, 파드를 중요(critical)로 표시하는 것은 축출을 완전히 방지하기 위함이 아니다. 이것은 단지 파드가 영구적으로 사용할 수 없게 되는 것만을 방지하기 위함이다. 중요로 표시한 스태틱(static) 파드는 축출될 수 없다. 반면, 중요로 표시한 일반적인(non-static) 파드의 경우 항상 다시 스케줄링된다.
파드를 중요로 표시하기 위해서는, 해당 파드에 대해 priorityClassName을 system-cluster-critical
이나 system-node-critical
로 설정한다. system-node-critical
은 가장 높은 우선 순위를 가지며, 심지어 system-cluster-critical
보다도 우선 순위가 높다.
이 페이지는 클러스터 컨트롤 플레인의 특정한 API 버전을 활성화하거나 비활성화하는 방법에 대해 설명한다.
API 서버에 --runtime-config=api/<version>
커맨드 라인 인자를 사용함으로서 특정한 API 버전을
활성화하거나 비활성화할 수 있다. 이 인자에 대한 값으로는 콤마로 구분된 API 버전의 목록을 사용한다.
뒤쪽에 위치한 값은 앞쪽의 값보다 우선적으로 사용된다.
이 runtime-config
커맨드 라인 인자에는 다음의 두 개의 특수 키를 사용할 수도 있다.
api/all
: 사용할 수 있는 모든 API를 선택한다.api/legacy
: 레거시 API만을 선택한다. 여기서 레거시 API란 명시적으로
사용이 중단된 모든 API를 가리킨다.예를 들어서, v1을 제외한 모든 API 버전을 비활성화하기 위해서는 kube-apiserver
에
--runtime-config=api/all=false,api/v1=true
인자를 사용한다.
kube-apiserver
컴포넌트에 대한 더 자세한 내용은 다음의 문서
를 참고한다.
이 페이지는 쿠버네티스 API를 사용하여 클러스터에 접근하는 방법을 보여준다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.쿠버네티스 API에 처음 접근하는 경우, 쿠버네티스
커맨드 라인 도구인 kubectl
을 사용한다.
클러스터에 접근하려면, 클러스터 위치를 알고 접근할 수 있는 자격 증명이 있어야 한다. 일반적으로, 시작하기 가이드를 통해 작업하거나, 다른 사람이 클러스터를 설정하고 자격 증명과 위치를 제공할 때 자동으로 설정된다.
다음의 명령으로 kubectl이 알고 있는 위치와 자격 증명을 확인한다.
kubectl config view
많은 예제는 kubectl 사용에 대한 소개를 제공한다. 전체 문서는 kubectl 매뉴얼에 있다.
kubectl은 API 서버 찾기와 인증을 처리한다. curl
이나 wget
과 같은 http 클라이언트 또는 브라우저를 사용하여 REST API에
직접 접근하려는 경우, API 서버를 찾고 인증할 수 있는 여러 가지 방법이 있다.
Go 또는 Python 클라이언트 라이브러리를 사용하면 프록시 모드에서 kubectl에 접근할 수 있다.
다음 명령은 kubectl을 리버스 프록시로 작동하는 모드에서 실행한다. API 서버 찾기와 인증을 처리한다.
다음과 같이 실행한다.
kubectl proxy --port=8080 &
자세한 내용은 kubectl 프록시를 참고한다.
그런 다음 curl, wget 또는 브라우저를 사용하여 API를 탐색할 수 있다.
curl http://localhost:8080/api/
출력은 다음과 비슷하다.
{
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.1.149:443"
}
]
}
다음과 같이 인증 토큰을 API 서버에 직접 전달하여 kubectl 프록시 사용을 피할 수 있다.
grep/cut
방식을 사용한다.
# .KUBECONFIG에 여러 콘텍스트가 있을 수 있으므로, 가능한 모든 클러스터를 확인한다.
kubectl config view -o jsonpath='{"Cluster name\tServer\n"}{range .clusters[*]}{.name}{"\t"}{.cluster.server}{"\n"}{end}'
# 위의 출력에서 상호 작용하려는 클러스터의 이름을 선택한다.
export CLUSTER_NAME="some_server_name"
# 클러스터 이름을 참조하는 API 서버를 가리킨다.
APISERVER=$(kubectl config view -o jsonpath="{.clusters[?(@.name==\"$CLUSTER_NAME\")].cluster.server}")
# 토큰 값을 얻는다
TOKEN=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='default')].data.token}"|base64 --decode)
# TOKEN으로 API 탐색
curl -X GET $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
출력은 다음과 비슷하다.
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.1.149:443"
}
]
}
jsonpath
방식을 사용한다.
APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
TOKEN=$(kubectl get secret $(kubectl get serviceaccount default -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.token}' | base64 --decode )
curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "10.0.1.149:443"
}
]
}
위의 예는 --insecure
플래그를 사용한다. 이로 인해 MITM 공격이
발생할 수 있다. kubectl이 클러스터에 접근하면 저장된 루트 인증서와
클라이언트 인증서를 사용하여 서버에 접근한다. (~/.kube
디렉터리에
설치된다.) 클러스터 인증서는 일반적으로 자체 서명되므로,
http 클라이언트가 루트 인증서를 사용하도록 하려면 특별한 구성이
필요할 수 있다.
일부 클러스터에서, API 서버는 인증이 필요하지 않다. 로컬 호스트에서 제공되거나, 방화벽으로 보호될 수 있다. 이에 대한 표준은 없다. 쿠버네티스 API에 대한 접근 제어는 클러스터 관리자로서 이를 구성하는 방법에 대해 설명한다. 이러한 접근 방식은 향후 고 가용성 지원과 충돌할 수 있다.
쿠버네티스는 공식적으로 Go, Python, Java, dotnet, Javascript 및 Haskell 용 클라이언트 라이브러리를 지원한다. 쿠버네티스 팀이 아닌 작성자가 제공하고 유지 관리하는 다른 클라이언트 라이브러리가 있다. 다른 언어에서 API에 접근하고 인증하는 방법에 대해서는 클라이언트 라이브러리를 참고한다.
go get k8s.io/client-go@kubernetes-<kubernetes-version-number>
어떤 버전이 지원되는지를 확인하려면 https://github.com/kubernetes/client-go/releases를 참고한다.import "k8s.io/client-go/kubernetes"
가 맞다.Go 클라이언트는 kubectl CLI가 API 서버를 찾아 인증하기 위해 사용하는 것과 동일한 kubeconfig 파일을 사용할 수 있다. 이 예제를 참고한다.
package main
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
// kubeconfig에서 현재 콘텍스트를 사용한다
// path-to-kubeconfig -- 예를 들어, /root/.kube/config
config, _ := clientcmd.BuildConfigFromFlags("", "<path-to-kubeconfig>")
// clientset을 생성한다
clientset, _ := kubernetes.NewForConfig(config)
// 파드를 나열하기 위해 API에 접근한다
pods, _ := clientset.CoreV1().Pods("").List(context.TODO(), v1.ListOptions{})
fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
}
애플리케이션이 클러스터 내의 파드로 배치된 경우, 파드 내에서 API 접근을 참고한다.
Python 클라이언트를 사용하려면, 다음 명령을 실행한다. pip install kubernetes
추가 설치 옵션은 Python Client Library 페이지를 참고한다.
Python 클라이언트는 kubectl CLI가 API 서버를 찾아 인증하기 위해 사용하는 것과 동일한 kubeconfig 파일을 사용할 수 있다. 이 예제를 참고한다.
from kubernetes import client, config
config.load_kube_config()
v1=client.CoreV1Api()
print("Listing pods with their IPs:")
ret = v1.list_pod_for_all_namespaces(watch=False)
for i in ret.items:
print("%s\t%s\t%s" % (i.status.pod_ip, i.metadata.namespace, i.metadata.name))
Java 클라이언트를 설치하려면, 다음을 실행한다.
# java 라이브러리를 클론한다
git clone --recursive https://github.com/kubernetes-client/java
# 프로젝트 아티팩트, POM 등을 설치한다
cd java
mvn install
어떤 버전이 지원되는지를 확인하려면 https://github.com/kubernetes-client/java/releases를 참고한다.
Java 클라이언트는 kubectl CLI가 API 서버를 찾아 인증하기 위해 사용하는 것과 동일한 kubeconfig 파일을 사용할 수 있다. 이 예제를 참고한다.
package io.kubernetes.client.examples;
import io.kubernetes.client.ApiClient;
import io.kubernetes.client.ApiException;
import io.kubernetes.client.Configuration;
import io.kubernetes.client.apis.CoreV1Api;
import io.kubernetes.client.models.V1Pod;
import io.kubernetes.client.models.V1PodList;
import io.kubernetes.client.util.ClientBuilder;
import io.kubernetes.client.util.KubeConfig;
import java.io.FileReader;
import java.io.IOException;
/**
* 쿠버네티스 클러스터 외부의 애플리케이션에서 Java API를 사용하는 방법에 대한 간단한 예
*
* <p>이것을 실행하는 가장 쉬운 방법: mvn exec:java
* -Dexec.mainClass="io.kubernetes.client.examples.KubeConfigFileClientExample"
*
*/
public class KubeConfigFileClientExample {
public static void main(String[] args) throws IOException, ApiException {
// KubeConfig의 파일 경로
String kubeConfigPath = "~/.kube/config";
// 파일시스템에서 클러스터 외부 구성인 kubeconfig 로드
ApiClient client =
ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath))).build();
// 전역 디폴트 api-client를 위에서 정의한 클러스터 내 클라이언트로 설정
Configuration.setDefaultApiClient(client);
// CoreV1Api는 전역 구성에서 디폴트 api-client를 로드
CoreV1Api api = new CoreV1Api();
// CoreV1Api 클라이언트를 호출한다
V1PodList list = api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null);
System.out.println("Listing all pods: ");
for (V1Pod item : list.getItems()) {
System.out.println(item.getMetadata().getName());
}
}
}
dotnet 클라이언트를 사용하려면, 다음 명령을 실행한다. dotnet add package KubernetesClient --version 1.6.1
추가 설치 옵션은 dotnet Client Library 페이지를 참고한다. 어떤 버전이 지원되는지를 확인하려면 https://github.com/kubernetes-client/csharp/releases를 참고한다.
dotnet 클라이언트는 kubectl CLI가 API 서버를 찾아 인증하기 위해 사용하는 것과 동일한 kubeconfig 파일을 사용할 수 있다. 이 예제를 참고한다.
using System;
using k8s;
namespace simple
{
internal class PodList
{
private static void Main(string[] args)
{
var config = KubernetesClientConfiguration.BuildDefaultConfig();
IKubernetes client = new Kubernetes(config);
Console.WriteLine("Starting Request!");
var list = client.ListNamespacedPod("default");
foreach (var item in list.Items)
{
Console.WriteLine(item.Metadata.Name);
}
if (list.Items.Count == 0)
{
Console.WriteLine("Empty!");
}
}
}
}
JavaScript 클라이언트를 설치하려면, 다음 명령을 실행한다. npm install @kubernetes/client-node
어떤 버전이 지원되는지를 확인하려면 https://github.com/kubernetes-client/javascript/releases를 참고한다.
JavaScript 클라이언트는 kubectl CLI가 API 서버를 찾아 인증하기 위해 사용하는 것과 동일한 kubeconfig 파일을 사용할 수 있다. 이 예제를 참고한다.
const k8s = require('@kubernetes/client-node');
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
k8sApi.listNamespacedPod('default').then((res) => {
console.log(res.body);
});
어떤 버전이 지원되는지를 확인하려면 https://github.com/kubernetes-client/haskell/releases를 참고한다.
Haskell 클라이언트는 kubectl CLI가 API 서버를 찾아 인증하기 위해 사용하는 것과 동일한 kubeconfig 파일을 사용할 수 있다. 이 예제를 참고한다.
exampleWithKubeConfig :: IO ()
exampleWithKubeConfig = do
oidcCache <- atomically $ newTVar $ Map.fromList []
(mgr, kcfg) <- mkKubeClientConfig oidcCache $ KubeConfigFile "/path/to/kubeconfig"
dispatchMime
mgr
kcfg
(CoreV1.listPodForAllNamespaces (Accept MimeJSON))
>>= print
Kubernetes v1.21 [stable]
이 문서는 쿠버네티스 클러스터에서 sysctl 인터페이스를 사용하여 커널 파라미터를 어떻게 구성하고, 사용하는지를 설명한다.
/
또는 .
를
sysctl 이름의 구분자로 사용하는 것을 지원한다.
예를 들어, 동일한 sysctl 이름을 kernel.shm_rmid_forced
와 같이 마침표를 구분자로 사용하여 나타내거나
kernel/shm_rmid_forced
와 같이 슬래시를 구분자로 사용하여 나타낼 수 있다.
sysctl 파라미터 변환에 대한 세부 사항은
리눅스 맨페이지 프로젝트의
sysctl.d(5) 페이지를 참고한다.
파드와 파드시큐리티폴리시(PodSecurityPolicy)에 대해 sysctl을 설정하는 기능에서는
아직 슬래시 구분자를 지원하지 않는다.쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
일부 단계에서는 실행 중인 클러스터의 kubelet에서 커맨드 라인 옵션을 재구성할 필요가 있다.
리눅스에서 sysctl 인터페이스는 관리자들이 런타임에 커널 파라미터를 수정할 수 있도록
허용한다. 파라미터는 /proc/sys
가상 파일 시스템을 통해 이용할 수 있다. 파라미터는
다음과 같은 다양한 서브 시스템을 포함한다.
kernel.
)net.
)vm.
)dev.
)모든 파라미터 리스트를 가져오려면 다음 명령을 실행한다.
sudo sysctl -a
sysctl은 safe sysctl과 unsafe sysctl로 구성되어 있다. safe sysctl은 적절한 네임스페이스 뿐만 아니라 동일한 노드의 파드 사이에 고립 되어야 한다. 즉, 하나의 파드에 safe sysctl을 설정한다는 것은 다음을 의미한다.
아직까지 대부분 네임스페이스된 sysctl은 safe sysctl로 고려되지 않았다. 다음 sysctl은 safe 명령을 지원한다.
kernel.shm_rmid_forced
,net.ipv4.ip_local_port_range
,net.ipv4.tcp_syncookies
,net.ipv4.ping_group_range
(쿠버네티스 1.18 이후),net.ipv4.ip_unprivileged_port_start
(쿠버네티스 1.22 이후).net.ipv4.tcp_syncookies
예시는 리눅스 커널 버전 4.4 또는 이하에서 네임스페이스되지 않는다.kubelet이 더 고립된 방법을 지원하면 추후 쿠버네티스 버전에서 확장될 것이다.
모든 safe sysctl은 기본적으로 활성화된다.
모든 unsafe sysctl은 기본적으로 비활성화되고, 노드별 기본 클러스터 관리자에 의해 수동으로 메뉴얼로 허용되어야 한다. unsafe sysctl이 비활성화된 파드는 스케줄링되지만, 시작에 실패한다.
위의 경고를 염두에 두고 클러스터 관리자는 고성능 또는 실시간 애플리케이션 조정과 같은 매우 특수한 상황에 대해 특정 unsafe sysctl을 허용할 수 있다. unsafe sysctl은 kubelet 플래그를 사용하여 노드별로 활성화된다. 예를 들면, 다음과 같다.
kubelet --allowed-unsafe-sysctls \
'kernel.msg*,net.core.somaxconn' ...
Minikube의 경우, extra-config
플래그를 통해 이 작업을 수행할 수 있다.
minikube start --extra-config="kubelet.allowed-unsafe-sysctls=kernel.msg*,net.core.somaxconn"...
네임스페이스 sysctl만 이 방법을 사용할 수 있다.
수많은 sysctl은 최근 리눅스 커널에서 네임스페이스 되어 있다. 이는 노드의 각 파드에 대해 개별적으로 설정할 수 있다는 것이다. 쿠버네티스의 파드 securityContext를 통해 네임스페이스 sysctl만 구성할 수 있다.
다음 sysctls는 네임스페이스로 알려져 있다. 이 목록은 이후 버전의 Linux 커널에서 변경될 수 있다.
kernel.shm*
,kernel.msg*
,kernel.sem
,fs.mqueue.*
,net.*
아래의 파라미터는 컨테이너 네트워킹 네임스페이스에서 설정할 수 있다.
그러나 예외가 존재한다. (예, net.netfilter.nf_conntrack_max
와 net.netfilter.nf_conntrack_expect_max
는
컨테이너 네트워킹 네임스페이스에서 설정되지만,
네임스페이스가 없다.)네임스페이스가 없는 sysctl은 node-level sysctl이라고 부른다. 이를 설정해야 한다면, 각 노드의 OS에서 수동으로 구성하거나 특권있는 컨테이너의 데몬셋을 사용하여야 한다.
네임스페이스 sysctl을 구성하기 위해서 파드 securityContext를 사용한다. securityContext는 동일한 파드의 모든 컨테이너에 적용된다.
이 예시는 safe sysctl kernel.shm_rmid_forced
와 두 개의 unsafe sysctl인
net.core.somaxconn
과 kernel.msgmax
를 설정하기 위해 파드 securityContext를 사용한다.
스펙에 따르면 safe sysctl과 unsafe sysctl 간
차이는 없다.
apiVersion: v1
kind: Pod
metadata:
name: sysctl-example
spec:
securityContext:
sysctls:
- name: kernel.shm_rmid_forced
value: "0"
- name: net.core.somaxconn
value: "1024"
- name: kernel.msgmax
value: "65536"
...
특별한 sysctl 설정이 있는 노드를 클러스터 내에서 _tainted_로 간주하고 sysctl 설정이 필요한 노드에만 파드를 예약하는 것이 좋다. 이를 구현하려면 쿠버네티스 테인트(taint)와 톨러레이션(toleration) 기능 을 사용하는 것이 좋다.
두 unsafe sysctl을 명시적으로 활성화하지 않은 노드에서 unsafe sysctl을 사용하는 파드가 시작되지 않는다. node-level sysctl과 마찬가지로 테인트와 톨러레이션 특징 또는 노드 테인트를 사용하여 해당 파드를 오른쪽 노드에 스케줄하는 것을 추천한다.
Kubernetes v1.21 [deprecated]
또한 파드시큐리티폴리시의 forbiddenSysctls
및/또는 allowedUnsafeSysctls
필드에
sysctl 또는 sysctl 패턴 목록을 지정하여 파드에서 설정할
수 있는 sysctl를 제어할 수 있다. sysctl 패턴은 kernel.*
과 같은 *
문자로 끝난다. *
문자 자체는
모든 sysctl와 일치한다.
기본적으로 모든 safe sysctl은 허용된다.
forbiddenSysctls
와 allowedUnsafeSysctls
는 모두 단순한 sysctl 이름 또는
sysctl 패턴 목록이다(*
로 끝남). *
문자는 모든 sysctl과 일치한다.
forbiddenSysctls
필드에는 특정 sysctl이 제외된다.
목록에서 safe sysctl과 unsafe sysctl의 조합을 금지할 수 있다.
sysctl 설정을 금지하기 위해서는 *
를 사용한다.
allowedUnsafeSysctls
필드에 unsafe sysctl을 지정하고 forbiddenSysctls
필드가
존재하지 않는 경우, 파드시큐리티폴리시를 사용하여
sysctl을 파드에서 사용할 수 있다.
파드시큐리티폴리시의 모든 unsafe sysctl을 설정하려면 *
를 사용한다.
이 두 필드를 겹치도록 구성하지 않는다. 이는 지정된 sysctl이 허용 및 금지됨을 의미한다.
이 예에서는 kernel.msg
접두사가 붙은 unsafe sysctl을 설정할 수 있으며,
kernel.shm_rmid_forced
sysctl의 설정을 허용하지 않는다.
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: sysctl-psp
spec:
allowedUnsafeSysctls:
- kernel.msg*
forbiddenSysctls:
- kernel.shm_rmid_forced
...
이 페이지는 쿠버네티스 클러스터에서 실행되는 서비스에 연결하는 방법을 보여준다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.쿠버네티스에서, 노드, 파드 및 서비스는 모두 고유한 IP를 가진다. 당신의 데스크탑 PC와 같은 클러스터 외부 장비에서는 클러스터 상의 노드 IP, 파드 IP, 서비스 IP로 라우팅되지 않아서 접근할 수 없을 것이다.
클러스터 외부에서 노드, 파드 및 서비스에 접속하기 위한 몇 가지 옵션이 있다.
NodePort
또는 LoadBalancer
타입의
서비스를 사용한다. 서비스와
kubectl expose 문서를 참고한다.일반적으로 kube-system에 의해 클러스터에 실행되는 몇 가지 서비스가 있다.
kubectl cluster-info
커맨드로 이 서비스의 리스트를 볼 수 있다.
kubectl cluster-info
출력은 다음과 비슷하다.
Kubernetes master is running at https://104.197.5.247
elasticsearch-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy
kibana-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kibana-logging/proxy
kube-dns is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kube-dns/proxy
grafana is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
heapster is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-heapster/proxy
각 서비스에 접근하기 위한 프록시-작업 URL이 표시된다.
예를 들어, 이 클러스터에는 https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/
로
접근할 수 있는 (Elasticsearch를 사용한) 클러스터 수준 로깅이 활성화되어 있다. 적합한 자격 증명이 전달되는 경우나 kubectl proxy를 통해 도달할 수 있다. 예를 들어 다음의 URL에서 확인할 수 있다.
http://localhost:8080/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/
.
위에서 언급한 것처럼, kubectl cluster-info
명령을 사용하여 서비스의 프록시 URL을 검색한다. 서비스 엔드포인트, 접미사 및 매개 변수를 포함하는 프록시 URL을 작성하려면, 서비스의 프록시 URL에 추가하면 된다.
http://
kubernetes_master_address
/api/v1/namespaces/
namespace_name
/services/
[https:]service_name[:port_name]
/proxy
포트에 대한 이름을 지정하지 않은 경우, URL에 port_name 을 지정할 필요가 없다. 또한, 이름이 지정된 포트와 지정되지 않은 포트 모두에 대해, port_name 자리에 포트 번호를 기재할 수도 있다.
기본적으로, API 서버는 서비스로의 프록시를 HTTP로 제공한다. HTTPS를 사용하려면, 서비스 이름 앞에 https:
를 추가한다.
http://<쿠버네티스_컨트롤_플레인_주소>/api/v1/namespaces/<네임스페이스_이름>/services/<서비스_이름>/proxy
URL에서 <서비스_이름>
이 지원하는 형식은 다음과 같다.
<서비스_이름>
- 기본 포트 또는 이름이 지정되지 않은 포트로 http를 사용하여 프록시<서비스_이름>:<포트_이름>
- 기재된 포트 이름 또는 포트 번호로 http를 사용하여 프록시https:<서비스_이름>:
- 기본 포트 또는 이름이 지정되지 않은 포트로 https를 사용하여 프록시(맨 끝의 콜론에 유의)https:<서비스_이름>:<포트_이름>
- 기재된 포트 이름 또는 포트 번호로 https를 사용하여 프록시Elasticsearch 서비스 엔드포인트 _search?q=user:kimchy
에 접근하려면, 다음을 사용한다.
http://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_search?q=user:kimchy
Elasticsearch 클러스터 상태 정보 _cluster/health?pretty=true
에 접근하려면, 다음을 사용한다.
https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_cluster/health?pretty=true
상태 정보는 다음과 비슷하다.
{
"cluster_name" : "kubernetes_logging",
"status" : "yellow",
"timed_out" : false,
"number_of_nodes" : 1,
"number_of_data_nodes" : 1,
"active_primary_shards" : 5,
"active_shards" : 5,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 5
}
https Elasticsearch 서비스 상태 정보 _cluster/health?pretty=true
에 접근하려면, 다음을 사용한다.
https://104.197.5.247/api/v1/namespaces/kube-system/services/https:elasticsearch-logging/proxy/_cluster/health?pretty=true
브라우저의 주소 표시줄에 apiserver 프록시 URL을 넣을 수 있다. 그러나,
이 페이지는 쿠버네티스 퍼시트턴트볼륨(PersistentVolume)의 반환 정책을 변경하는 방법을 보여준다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.퍼시스턴트볼륨은 "Retain(보존)", "Recycle(재활용)", "Delete(삭제)" 를 포함한
다양한 반환 정책을 갖는다. 동적으로 프로비저닝 된 퍼시스턴트볼륨의 경우
기본 반환 정책은 "Delete" 이다. 이는 사용자가 해당 PersistentVolumeClaim
을 삭제하면,
동적으로 프로비저닝 된 볼륨이 자동적으로 삭제됨을 의미한다.
볼륨에 중요한 데이터가 포함된 경우, 이러한 자동 삭제는 부적절 할 수 있다.
이 경우에는, "Retain" 정책을 사용하는 것이 더 적합하다.
"Retain" 정책에서, 사용자가 퍼시스턴트볼륨클레임을 삭제할 경우 해당하는
퍼시스턴트볼륨은 삭제되지 않는다.
대신, Released
단계로 이동되어, 모든 데이터를 수동으로 복구할 수 있다.
사용자의 클러스터에서 퍼시스턴트볼륨을 조회한다.
kubectl get pv
결과는 아래와 같다.
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-b6efd8da-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim1 manual 10s
pvc-b95650f8-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim2 manual 6s
pvc-bb3ca71d-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim3 manual 3s
이 목록은 동적으로 프로비저닝 된 볼륨을 쉽게 식별할 수 있도록 각 볼륨에 바인딩 되어 있는 퍼시스턴트볼륨클레임(PersistentVolumeClaim)의 이름도 포함한다.
사용자의 퍼시스턴트볼륨 중 하나를 선택한 후에 반환 정책을 변경한다.
kubectl patch pv <your-pv-name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
<your-pv-name>
는 사용자가 선택한 퍼시스턴트볼륨의 이름이다.
윈도우에서는, 공백이 포함된 모든 JSONPath 템플릿에 _겹_ 따옴표를 사용해야 한다.(bash에 대해 위에서 표시된 홑 따옴표가 아니다.) 따라서 템플릿의 모든 표현식에서 홑 따옴표를 쓰거나, 이스케이프 처리된 겹 따옴표를 써야 한다. 예를 들면 다음과 같다.
kubectl patch pv <your-pv-name> -p "{\"spec\":{\"persistentVolumeReclaimPolicy\":\"Retain\"}}"
선택한 PersistentVolume이 올바른 정책을 갖는지 확인한다.
kubectl get pv
결과는 아래와 같다.
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-b6efd8da-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim1 manual 40s
pvc-b95650f8-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim2 manual 36s
pvc-bb3ca71d-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Retain Bound default/claim3 manual 33s
위 결과에서, default/claim3
클레임과 바인딩 되어 있는 볼륨이 Retain
반환 정책을
갖는 것을 볼 수 있다. 사용자가 default/claim3
클레임을 삭제할 경우,
볼륨은 자동으로 삭제 되지 않는다.
.spec.persistentVolumeReclaimPolicy
필드에 주의한다.이 페이지는 메모리 요청량 과 메모리 상한 을 컨테이너에 어떻게 지정하는지 보여준다. 컨테이너는 요청량 만큼의 메모리 확보가 보장되나 상한보다 더 많은 메모리는 사용할 수 없다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.클러스터의 각 노드에 최소 300 MiB 메모리가 있어야 한다.
이 페이지의 몇 가지 단계를 수행하기 위해서는 클러스터 내 metrics-server 서비스 실행이 필요하다. 이미 실행 중인 metrics-server가 있다면 다음 단계를 건너뛸 수 있다.
Minikube를 사용 중이라면, 다음 명령어를 실행해 metric-server를 활성화할 수 있다.
minikube addons enable metrics-server
metric-server가 실행 중인지 확인하거나 다른 제공자의 리소스 메트릭 API (metrics.k8s.io
)를 확인하기 위해
다음의 명령어를 실행한다.
kubectl get apiservices
리소스 메트릭 API를 사용할 수 있다면 출력에
metrics.k8s.io
에 대한 참조가 포함되어 있다.
NAME
v1beta1.metrics.k8s.io
이 예제에서 생성할 자원과 클러스터 내 나머지를 분리하기 위해 네임스페이스를 생성한다.
kubectl create namespace mem-example
컨테이너에 메모리 요청량을 지정하기 위해서는 컨테이너의 리소스 매니페스트에
resources:requests
필드를 포함한다. 리소스 상한을 지정하기 위해서는
resources:limits
필드를 포함한다.
이 예제에서 하나의 컨테이너를 가진 파드를 생성한다. 생성된 컨테이너는 100 MiB 메모리 요청량과 200 MiB 메모리 상한을 갖는다. 이 것이 파드 구성 파일이다.
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
namespace: mem-example
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
구성 파일 내 args
섹션은 컨테이너가 시작될 때 아규먼트를 제공한다.
"--vm-bytes", "150M"
아규먼트는 컨테이너가 150 MiB 할당을 시도 하도록 한다.
파드 생성:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example
파드 컨테이너가 실행 중인지 확인:
kubectl get pod memory-demo --namespace=mem-example
파드에 대한 자세한 정보 보기:
kubectl get pod memory-demo --output=yaml --namespace=mem-example
출력은 파드 내 하나의 컨테이너에 100MiB 메모리 요청량과 200 MiB 메모리 상한이 있는 것을 보여준다.
...
resources:
limits:
memory: 200Mi
requests:
memory: 100Mi
...
kubectl top
을 실행하여 파드 메트릭 가져오기:
kubectl top pod memory-demo --namespace=mem-example
출력은 파드가 약 150 MiB 해당하는 약 162,900,000 바이트 메모리를 사용하는 것을 보여준다. 이는 파드의 100 MiB 요청 보다 많으나 파드의 200 MiB 상한보다는 적다.
NAME CPU(cores) MEMORY(bytes)
memory-demo <something> 162856960
파드 삭제:
kubectl delete pod memory-demo --namespace=mem-example
노드 내 메모리가 충분하다면 컨테이너는 지정한 요청량보다 많은 메모리를 사용 할 수 있다. 그러나 컨테이너는 지정한 메모리 상한보다 많은 메모리를 사용할 수 없다. 만약 컨테이너가 지정한 메모리 상한보다 많은 메모리를 할당하면 해당 컨테이너는 종료 대상 후보가 된다. 만약 컨테이너가 지속적으로 지정된 상한보다 많은 메모리를 사용한다면, 해당 컨테이너는 종료된다. 만약 종료된 컨테이너가 재실행 가능하다면 다른 런타임 실패와 마찬가지로 kubelet에 의해 재실행된다.
이 예제에서는 상한보다 많은 메모리를 할당하려는 파드를 생성한다. 이 것은 50 MiB 메모리 요청량과 100 MiB 메모리 상한을 갖는 하나의 컨테이너를 갖는 파드의 구성 파일이다.
apiVersion: v1
kind: Pod
metadata:
name: memory-demo-2
namespace: mem-example
spec:
containers:
- name: memory-demo-2-ctr
image: polinux/stress
resources:
requests:
memory: "50Mi"
limits:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]
구성 파일의 args
섹션에서 컨테이너가
100 MiB 상한을 훨씬 초과하는 250 MiB의 메모리를 할당하려는 것을 볼 수 있다.
파드 생성:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example
파드에 대한 자세한 정보 보기:
kubectl get pod memory-demo-2 --namespace=mem-example
이 시점에 컨테이너가 실행되거나 종료되었을 수 있다. 컨테이너가 종료될 때까지 이전의 명령을 반복한다.
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 24s
컨테이너 상태의 상세 상태 보기:
kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example
컨테이너가 메모리 부족 (OOM) 으로 종료되었음이 출력된다.
lastState:
terminated:
containerID: 65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
exitCode: 137
finishedAt: 2017-06-20T20:52:19Z
reason: OOMKilled
startedAt: null
이 예제에서 컨테이너는 재실행 가능하여 kubelet에 의해 재실행된다. 컨테이너가 종료되었다 재실행되는 것을 보기 위해 다음 명령을 몇 번 반복한다.
kubectl get pod memory-demo-2 --namespace=mem-example
출력은 컨테이너의 종료, 재실행, 재종료, 재실행 등을 보여준다.
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 0/1 OOMKilled 1 37s
kubectl get pod memory-demo-2 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-2 1/1 Running 2 40s
파드 내역에 대한 상세 정보 보기:
kubectl describe pod memory-demo-2 --namespace=mem-example
컨테이너가 반복적으로 시작하고 실패 하는 출력을 보여준다.
... Normal Created Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff Back-off restarting failed container
클러스터 노드에 대한 자세한 정보 보기:
kubectl describe nodes
출력에는 컨테이너가 메모리 부족으로 종료된 기록이 포함된다.
Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child
파드 삭제:
kubectl delete pod memory-demo-2 --namespace=mem-example
메모리 요청량과 상한은 컨테이너와 관련있지만, 파드가 가지는 메모리 요청량과 상한으로 이해하면 유용하다. 파드의 메모리 요청량은 파드 내 모든 컨테이너의 메모리 요청량의 합이다. 마찬가지로 파드의 메모리 상한은 파드 내 모든 컨테이너의 메모리 상한의 합이다.
파드는 요청량을 기반하여 스케줄링된다. 노드에 파드의 메모리 요청량을 충족하기에 충분한 메모리가 있는 경우에만 파드가 노드에서 스케줄링된다.
이 예제에서는 메모리 요청량이 너무 커 클러스터 내 모든 노드의 용량을 초과하는 파드를 생성한다. 다음은 클러스터 내 모든 노드의 용량을 초과할 수 있는 1000 GiB 메모리 요청을 포함하는 컨테이너를 갖는 파드의 구성 파일이다.
apiVersion: v1
kind: Pod
metadata:
name: memory-demo-3
namespace: mem-example
spec:
containers:
- name: memory-demo-3-ctr
image: polinux/stress
resources:
limits:
memory: "1000Gi"
requests:
memory: "1000Gi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
파드 생성:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example
파드 상태 보기:
kubectl get pod memory-demo-3 --namespace=mem-example
파드 상태가 PENDING 상태임이 출력된다. 즉 파드는 어떤 노드에서도 실행되도록 스케줄 되지 않고 PENDING가 계속 지속된다.
kubectl get pod memory-demo-3 --namespace=mem-example
NAME READY STATUS RESTARTS AGE
memory-demo-3 0/1 Pending 0 25s
이벤트를 포함한 파드 상세 정보 보기:
kubectl describe pod memory-demo-3 --namespace=mem-example
출력은 노드 내 메모리가 부족하여 파드가 스케줄링될 수 없음을 보여준다.
Events:
... Reason Message
------ -------
... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory (3).
메모리 리소스는 byte 단위로 측정된다. 다음 접미사 중 하나로 정수 또는 고정 소수점으로 메모리를 표시할 수 있다. E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki. 예를 들어 다음은 거의 유사한 값을 나타낸다.
128974848, 129e6, 129M , 123Mi
파드 삭제:
kubectl delete pod memory-demo-3 --namespace=mem-example
컨테이너에 메모리 상한을 지정하지 않으면 다음 중 하나가 적용된다.
컨테이너가 사용할 수 있는 메모리 상한은 없다. 컨테이너가 실행 중인 노드에서 사용 가능한 모든 메모리를 사용하여 OOM Killer가 실행될 수 있다. 또한 메모리 부족으로 인한 종료 시 메모리 상한이 없는 컨테이너가 종료될 가능성이 크다.
기본 메모리 상한을 갖는 네임스페이스 내에서 실행중인 컨테이너는 자동으로 기본 메모리 상한이 할당된다. 클러스터 관리자들은 LimitRange를 사용해 메모리 상한의 기본 값을 지정 가능하다.
클러스터에서 실행되는 컨테이너에 메모리 요청량과 상한을 구성하여 클러스터 내 노드들의 메모리 리소스를 효율적으로 사용할 수 있게 할 수 있다. 파드의 메모리 요청량을 적게 유지하여 파드가 높은 확률로 스케줄링 될 수 있도록 한다. 메모리 상한이 메모리 요청량보다 크면 다음 두 가지가 수행된다.
네임스페이스를 지운다. 이 작업을 통해 네임스페이스 내 생성했던 모든 파드들은 삭제된다.
kubectl delete namespace mem-example
Kubernetes v1.18 [stable]
이 페이지에서는 윈도우 노드에서 실행될 파드 및 컨테이너에 runAsUserName
설정을 사용하는 방법을 소개한다. 이는 리눅스 관련 runAsUser
설정과 거의 동일하여, 컨테이너의 기본값과 다른 username으로 애플리케이션을 실행할 수 있다.
쿠버네티스 클러스터가 있어야 하며 클러스터와 통신하도록 kubectl 명령줄 도구를 구성해야 한다. 클러스터에는 윈도우 워커 노드가 있어야 하고, 해당 노드에서 윈도우 워크로드를 실행하는 컨테이너의 파드가 스케쥴 된다.
파드의 컨테이너 프로세스를 실행할 username을 지정하려면 파드 명세에 securityContext
필드 (PodSecurityContext) 를 포함시키고, 그 안에 runAsUserName
필드를 포함하는 windowsOptions
(WindowsSecurityContextOptions) 필드를 추가한다.
파드에 지정하는 윈도우 보안 컨텍스트 옵션은 파드의 모든 컨테이너 및 초기화 컨테이너에 적용된다.
다음은 runAsUserName
필드가 설정된 윈도우 파드의 구성 파일이다.
apiVersion: v1
kind: Pod
metadata:
name: run-as-username-pod-demo
spec:
securityContext:
windowsOptions:
runAsUserName: "ContainerUser"
containers:
- name: run-as-username-demo
image: mcr.microsoft.com/windows/servercore:ltsc2019
command: ["ping", "-t", "localhost"]
nodeSelector:
kubernetes.io/os: windows
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/windows/run-as-username-pod.yaml
파드의 컨테이너가 실행 중인지 확인한다.
kubectl get pod run-as-username-pod-demo
실행 중인 컨테이너의 셸에 접근한다.
kubectl exec -it run-as-username-pod-demo -- powershell
셸이 올바른 username인 사용자로 실행 중인지 확인한다.
echo $env:USERNAME
결과는 다음과 같다.
ContainerUser
컨테이너의 프로세스를 실행할 username을 지정하려면, 컨테이너 매니페스트에 securityContext
필드 (SecurityContext) 를 포함시키고 그 안에 runAsUserName
필드를 포함하는 windowsOptions
(WindowsSecurityContextOptions) 필드를 추가한다.
컨테이너에 지정하는 윈도우 보안 컨텍스트 옵션은 해당 개별 컨테이너에만 적용되며 파드 수준에서 지정한 설정을 재정의한다.
다음은 한 개의 컨테이너에 runAsUserName
필드가 파드 수준 및 컨테이너 수준에서 설정되는 파드의 구성 파일이다.
apiVersion: v1
kind: Pod
metadata:
name: run-as-username-container-demo
spec:
securityContext:
windowsOptions:
runAsUserName: "ContainerUser"
containers:
- name: run-as-username-demo
image: mcr.microsoft.com/windows/servercore:ltsc2019
command: ["ping", "-t", "localhost"]
securityContext:
windowsOptions:
runAsUserName: "ContainerAdministrator"
nodeSelector:
kubernetes.io/os: windows
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/windows/run-as-username-container.yaml
파드의 컨테이너가 실행 중인지 확인한다.
kubectl get pod run-as-username-container-demo
실행 중인 컨테이너의 셸에 접근한다.
kubectl exec -it run-as-username-container-demo -- powershell
셸이 사용자에게 올바른 username(컨테이너 수준에서 설정된 사용자)을 실행 중인지 확인한다.
echo $env:USERNAME
결과는 다음과 같다.
ContainerAdministrator
이 기능을 사용하려면 runAsUserName
필드에 설정된 값이 유효한 username이어야 한다. 형식은 DOMAIN\USER
여야하고, 여기서 DOMAIN\
은 선택 사항이다. 윈도우 username은 대소문자를 구분하지 않는다. 또한 DOMAIN
및 USER
와 관련된 몇 가지 제약사항이 있다.
runAsUserName
필드는 비워 둘 수 없으며 제어 문자를 포함할 수 없다. (ASCII 값: 0x00-0x1F
, 0x7F
)DOMAIN
은 NetBios 이름 또는 DNS 이름이어야 하며 각각 고유한 제한이 있다..
(마침표)으로 시작할 수 없으며 다음 문자를 포함할 수 없다. \ / : * ? " < > |
.
), 대시(-
)로만 구성되며, 마침표 또는 대시로 시작하거나 끝날 수 없다.USER
는 최대 20자이며, 오직 마침표나 공백들로는 구성할 수 없고, 다음 문자는 포함할 수 없다. " / \ [ ] : ; | = , + * ? < > @
.runAsUserName
필드에 허용되는 값의 예 : ContainerAdministrator
,ContainerUser
, NT AUTHORITY\NETWORK SERVICE
, NT AUTHORITY\LOCAL SERVICE
.
이러한 제약사항에 대한 자세한 내용은 여기 와 여기를 확인한다.
Kubernetes v1.18 [stable]
이 페이지는 윈도우 노드에서 실행되는 파드와 컨테이너용으로 그룹 관리 서비스 어카운트(Group Managed Service Accounts, GMSA)를 구성하는 방법을 소개한다. 그룹 관리 서비스 어카운트는 자동 암호 관리, 단순화된 서비스 사용자 이름(service principal name, SPN) 관리, 여러 서버에 걸쳐 다른 관리자에게 관리를 위임하는 기능을 제공하는 특정한 유형의 액티브 디렉터리(Active Directory) 계정이다.
쿠버네티스에서 GMSA 자격 증명 사양은 쿠버네티스 클러스터 전체 범위에서 사용자 정의 리소스(Custom Resources)로 구성된다. 윈도우 파드 및 파드 내의 개별 컨테이너들은 다른 윈도우 서비스와 상호 작용할 때 도메인 기반 기능(예: Kerberos 인증)에 GMSA를 사용하도록 구성할 수 있다.
쿠버네티스 클러스터가 있어야 하며 클러스터와 통신하도록 kubectl
커맨드라인 툴을 구성해야 한다. 클러스터에는 윈도우 워커 노드가 있어야 한다. 이 섹션에서는 각 클러스터에 대해 한 번씩 필요한 일련의 초기 단계를 다룬다.
GMSA 자격 증명 사양 리소스에 대한 커스텀리소스데피니션(CustomResourceDefinition, CRD)을 클러스터에서 구성하여 사용자 정의 리소스 유형 GMSACredentialSpec
을 정의해야 한다. GMSA CRD YAML을 다운로드하고 gmsa-crd.yaml로 저장한다.
다음, kubectl apply -f gmsa-crd.yaml
로 CRD를 설치한다.
쿠버네티스 클러스터에서 두 개의 웹훅을 구성하여 파드 또는 컨테이너 수준에서 GMSA 자격 증명 사양 참조를 채우고 검증한다.
변형(mutating) 웹훅은 (파드 사양의 이름별로) GMSA에 대한 참조를 파드 사양 내 JSON 형식의 전체 자격 증명 사양으로 확장한다.
검증(validating) 웹훅은 GMSA에 대한 모든 참조가 파드 서비스 어카운트에서 사용하도록 승인되었는지 확인한다.
위의 웹훅 및 관련 오브젝트를 설치하려면 다음 단계가 필요하다.
인증서 키 쌍 생성 (웹훅 컨테이너가 클러스터와 통신할 수 있도록 하는데 사용됨)
위의 인증서로 시크릿을 설치
핵심 웹훅 로직에 대한 디플로이먼트(deployment)를 생성
디플로이먼트를 참조하여 검증 및 변경 웹훅 구성을 생성
스크립트를 사용하여 GMSA 웹훅과 위에서 언급한 관련 오브젝트를 배포 및 구성할 수 있다. 스크립트는 --dry-run=server
옵션으로 실행되어 클러스터에 대한 변경 사항을 검토할 수 있다.
스크립트에서 사용하는 YAML 템플릿을 사용하여 웹훅 및 (파라미터를 적절히 대체하여) 관련 오브젝트를 수동으로 배포할 수도 있다.
쿠버네티스의 파드가 GMSA를 사용하도록 구성되기 전에 윈도우 GMSA 문서에 설명된 대로 액티브 디렉터리에서 원하는 GMSA를 프로비저닝해야 한다. 윈도우 GMSA 문서에 설명된 대로 원하는 GMSA와 연결된 시크릿 자격 증명에 접근하려면 (쿠버네티스 클러스터의 일부인) 윈도우 워커 노드를 액티브 디렉터리에서 구성해야 한다.
(앞에서 설명한 대로) GMSACredentialSpec CRD를 설치하면 GMSA 자격 증명 사양이 포함된 사용자 정의 리소스를 구성할 수 있다. GMSA 자격 증명 사양에는 시크릿 또는 민감한 데이터가 포함되어 있지 않다. 이것은 컨테이너 런타임이 원하는 윈도우 컨테이너 GMSA를 설명하는 데 사용할 수 있는 정보이다. GMSA 자격 증명 사양은 PowerShell 스크립트 유틸리티를 사용하여 YAML 형식으로 생성할 수 있다.
다음은 JSON 형식으로 GMSA 자격 증명 사양 YAML을 수동으로 생성한 다음 변환하는 단계이다.
CredentialSpec 모듈 가져오기(import): ipmo CredentialSpec.psm1
New-CredentialSpec
을 사용하여 JSON 형식의 자격 증명 사양을 만든다. WebApp1이라는 GMSA 자격 증명 사양을 만들려면 New-CredentialSpec -Name WebApp1 -AccountName WebApp1 -Domain $(Get-ADDomain -Current LocalComputer)
를 호출한다.
Get-CredentialSpec
을 사용하여 JSON 파일의 경로를 표시한다.
credspec 파일을 JSON에서 YAML 형식으로 변환하고 필요한 헤더 필드 apiVersion
, kind
, metadata
, credspec
을 적용하여 쿠버네티스에서 구성할 수 있는 GMSACredentialSpec 사용자 정의 리소스로 만든다.
다음 YAML 구성은 gmsa-WebApp1
이라는 GMSA 자격 증명 사양을 설명한다.
apiVersion: windows.k8s.io/v1
kind: GMSACredentialSpec
metadata:
name: gmsa-WebApp1 #임의의 이름이지만 참조로 사용된다.
credspec:
ActiveDirectoryConfig:
GroupManagedServiceAccounts:
- Name: WebApp1 #GMSA 계정의 사용자 이름
Scope: CONTOSO #NETBIOS 도메인 명
- Name: WebApp1 #GMSA 계정의 사용자 이름
Scope: contoso.com #DNS 도메인 명
CmsPlugins:
- ActiveDirectory
DomainJoinConfig:
DnsName: contoso.com #DNS 도메인 명
DnsTreeName: contoso.com #DNS 도메인 명 루트
Guid: 244818ae-87ac-4fcd-92ec-e79e5252348a #GUID
MachineAccountName: WebApp1 #GMSA 계정의 사용자 이름
NetBiosName: CONTOSO #NETBIOS 도메인 명
Sid: S-1-5-21-2126449477-2524075714-3094792973 #SID of GMSA
위의 자격 증명 사양 리소스는 gmsa-Webapp1-credspec.yaml
로 저장되고 kubectl apply -f gmsa-Webapp1-credspec.yml
을 사용하여 클러스터에 적용될 수 있다.
각 GMSA 자격 증명 사양 리소스에 대해 cluster role을 정의해야 한다. 이것은 일반적으로 서비스 어카운트인 주체에 의해 특정 GMSA 리소스에 대한 use
동사를 승인한다. 다음 예는 위에서 gmsa-WebApp1
자격 증명 사양의 사용을 승인하는 클러스터 롤(cluster role)을 보여준다. 파일을 gmsa-webapp1-role.yaml로 저장하고 kubectl apply -f gmsa-webapp1-role.yaml
을 사용하여 적용한다.
#credspec을 읽을 Role 생성
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: webapp1-role
rules:
- apiGroups: ["windows.k8s.io"]
resources: ["gmsacredentialspecs"]
verbs: ["use"]
resourceNames: ["gmsa-WebApp1"]
(파드가 사용하게 되는) 서비스 어카운트는 위에서 생성한 클러스터 롤에 바인딩되어야 한다. 이렇게 하면 서비스 어카운트가 원하는 GMSA 자격 증명 사양 리소스를 사용할 수 있다. 다음은 위에서 생성한 gmsa-WebApp1
자격 증명 사양 리소스를 사용하기 위해 webapp1-role
클러스터 롤에 바인딩되는 기본(default) 서비스 어카운트이다.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: allow-default-svc-account-read-on-gmsa-WebApp1
namespace: default
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
kind: ClusterRole
name: webapp1-role
apiGroup: rbac.authorization.k8s.io
파드 사양 필드 securityContext.windowsOptions.gmsaCredentialSpecName
은 파드 사양에서 원하는 GMSA 자격 증명 사양 사용자 정의 리소스에 대한 참조를 지정하는 데 사용된다. 이렇게 하면 지정된 GMSA를 사용하도록 파드 사양의 모든 컨테이너가 구성된다. 다음은 gmsa-WebApp1
을 참조하도록 채워진 어노테이션이 있는 샘플 파드 사양이다.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: with-creds
name: with-creds
namespace: default
spec:
replicas: 1
selector:
matchLabels:
run: with-creds
template:
metadata:
labels:
run: with-creds
spec:
securityContext:
windowsOptions:
gmsaCredentialSpecName: gmsa-webapp1
containers:
- image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
imagePullPolicy: Always
name: iis
nodeSelector:
kubernetes.io/os: windows
파드 사양의 개별 컨테이너는 컨테이너별 securityContext.windowsOptions.gmsaCredentialSpecName
필드를 사용하여 원하는 GMSA credspec을 지정할 수도 있다. 다음은 예이다.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: with-creds
name: with-creds
namespace: default
spec:
replicas: 1
selector:
matchLabels:
run: with-creds
template:
metadata:
labels:
run: with-creds
spec:
containers:
- image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
imagePullPolicy: Always
name: iis
securityContext:
windowsOptions:
gmsaCredentialSpecName: gmsa-Webapp1
nodeSelector:
kubernetes.io/os: windows
(위에서 설명한 대로) GMSA 필드가 채워진 파드 사양이 클러스터에 적용되면 다음과 같은 일련의 이벤트가 발생한다.
변형 웹훅은 GMSA 자격 증명 사양 리소스에 대한 모든 참조를 확인하고 GMSA 자격 증명 사양의 내용으로 확장한다.
검증 웹훅은 파드와 연결된 서비스 어카운트가 지정된 GMSA 자격 증명 사양의 use
동사에 대해 승인되었는지 확인한다.
컨테이너 런타임은 컨테이너가 액티브 디렉터리에서 GMSA의 ID를 가정하고 해당 ID를 사용하여 도메인의 서비스에 접근할 수 있도록 지정된 GMSA 자격 증명 사양으로 각 윈도우 컨테이너를 구성한다.
파드에서 호스트네임 또는 FQDN을 사용하여 SMB 공유에 연결할 때 문제를 겪고 있으나, IPv4 주소로는 해당 공유에 접속이 가능한 상황이라면, 윈도우 노드에 다음 레지스트리 키를 등록했는지 확인한다.
reg add "HKLM\SYSTEM\CurrentControlSet\Services\hns\State" /v EnableCompartmentNamespace /t REG_DWORD /d 1
그런 다음 동작 변경 사항을 적용하려면 실행 중인 파드를 다시 생성해야 한다. 이 레지스트리 키가 어떻게 사용되는지에 대한 자세한 정보는 여기에서 볼 수 있다.
GMSA가 사용자 환경에서 작동하도록 하는 데 어려움이 있는 경우 취할 수 있는 몇 가지 문제 해결 단계가 있다.
먼저 credspec이 파드에 전달되었는지 확인한다. 이렇게 하려면 파드 중 하나에서 exec
를 실행하고 nltest.exe /parentdomain
명령의 출력을 확인해야 한다.
아래 예에서 파드는 credspec을 올바르게 가져오지 못했다.
kubectl exec -it iis-auth-7776966999-n5nzr powershell.exe
nltest.exe /parentdomain
는 다음과 같은 오류를 발생시킨다.
Getting parent domain failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE
파드가 credspec을 올바르게 가져오면 다음으로 도메인과의 통신을 확인한다. 먼저 파드 내부에서 nslookup을 빠르게 수행하여 도메인의 루트를 찾는다.
이것은 다음의 세 가지를 의미한다.
DNS 및 통신 테스트를 통과하면 다음으로 파드가 도메인과 보안 채널 통신을 설정했는지 확인해야 한다. 이렇게 하려면 파드에서 다시 exec
를 실행하고 nltest.exe /query
명령을 실행한다.
nltest.exe /query
결과는 다음과 같다.
I_NetLogonControl failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE
이것은 어떤 이유로 파드가 credspec에 지정된 계정을 사용하여 도메인에 로그온할 수 없음을 알려준다. 다음을 실행하여 보안 채널 복구를 시도할 수 있다.
nltest /sc_reset:domain.example
명령이 성공하면 다음과 유사한 출력이 표시된다.
Flags: 30 HAS_IP HAS_TIMESERV
Trusted DC Name \\dc10.domain.example
Trusted DC Connection Status Status = 0 0x0 NERR_Success
The command completed successfully
위의 방법으로 오류가 수정되면 다음 수명 주기 훅(hook)을 파드 사양에 추가하여 단계를 자동화할 수 있다. 오류가 수정되지 않은 경우 credspec을 다시 검사하여 정확하고 완전한지 확인해야 한다.
image: registry.domain.example/iis-auth:1809v1
lifecycle:
postStart:
exec:
command: ["powershell.exe","-command","do { Restart-Service -Name netlogon } while ( $($Result = (nltest.exe /query); if ($Result -like '*0x0 NERR_Success*') {return $true} else {return $false}) -eq $false)"]
imagePullPolicy: IfNotPresent
위의 lifecycle
섹션을 파드 사양에 추가하면, 파드는 nltest.exe /query
명령이 오류 없이 종료될 때까지 나열된 명령을 실행하여 netlogon
서비스를 다시 시작한다.
이 페이지는 특정 서비스 품질(QoS) 클래스를 할당하기 위해 어떻게 파드를 구성해야 하는지 보여준다. 쿠버네티스는 QoS 클래스를 사용하여 파드 스케줄링과 축출을 결정한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.쿠버네티스가 파드를 생성할 때, 파드에 다음의 QoS 클래스 중 하나를 할당한다.
이 연습에서 생성한 리소스가 클러스터의 나머지와 격리되도록 네임스페이스를 생성한다.
kubectl create namespace qos-example
파드에 Guaranteed QoS 클래스 할당을 위한 전제 조건은 다음과 같다.
이러한 제약은 초기화 컨테이너와 앱 컨테이너 모두에 동일하게 적용된다.
다음은 하나의 컨테이너를 갖는 파드의 구성 파일이다. 해당 컨테이너는 메모리 상한과 메모리 요청량을 갖고 있고, 200MiB로 동일하다. 해당 컨테이너는 CPU 상한과 CPU 요청량을 가지며, 700 milliCPU로 동일하다.
apiVersion: v1
kind: Pod
metadata:
name: qos-demo
namespace: qos-example
spec:
containers:
- name: qos-demo-ctr
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod.yaml --namespace=qos-example
파드의 상세 정보를 본다.
kubectl get pod qos-demo --namespace=qos-example --output=yaml
출력 결과는 쿠버네티스가 파드에 Guaranteed QoS 클래스를 부여했음을 보여준다. 또한 파드의 컨테이너가 메모리 요청량과 일치하는 메모리 상한을 가지며, CPU 요청량과 일치하는 CPU 상한을 갖고 있음을 확인할 수 있다.
spec:
containers:
...
resources:
limits:
cpu: 700m
memory: 200Mi
requests:
cpu: 700m
memory: 200Mi
...
status:
qosClass: Guaranteed
파드를 삭제한다.
kubectl delete pod qos-demo --namespace=qos-example
다음의 경우 파드에 Burstable QoS 클래스가 부여된다.
컨테이너가 하나인 파드의 구성 파일은 다음과 같다. 컨테이너는 200MiB의 메모리 상한과 100MiB의 메모리 요청량을 가진다.
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-2
namespace: qos-example
spec:
containers:
- name: qos-demo-2-ctr
image: nginx
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-2.yaml --namespace=qos-example
파드의 상세 정보를 본다.
kubectl get pod qos-demo-2 --namespace=qos-example --output=yaml
출력 결과는 쿠버네티스가 파드에 Burstable QoS 클래스를 부여했음을 보여준다.
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: qos-demo-2-ctr
resources:
limits:
memory: 200Mi
requests:
memory: 100Mi
...
status:
qosClass: Burstable
파드를 삭제한다.
kubectl delete pod qos-demo-2 --namespace=qos-example
파드에 QoS 클래스 BestEffort를 제공하려면, 파드의 컨테이너에 메모리 또는 CPU의 상한이나 요청량이 없어야 한다.
컨테이너가 하나인 파드의 구성 파일이다. 해당 컨테이너는 메모리 또는 CPU의 상한이나 요청량을 갖지 않는다.
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-3
namespace: qos-example
spec:
containers:
- name: qos-demo-3-ctr
image: nginx
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-3.yaml --namespace=qos-example
파드의 상세 정보를 본다.
kubectl get pod qos-demo-3 --namespace=qos-example --output=yaml
출력 결과는 쿠버네티스가 파드에 BestEffort QoS 클래스를 부여했음을 보여준다.
spec:
containers:
...
resources: {}
...
status:
qosClass: BestEffort
파드를 삭제한다.
kubectl delete pod qos-demo-3 --namespace=qos-example
컨테이너가 두 개인 파드의 구성 파일이다. 한 컨테이너는 200MiB의 메모리 요청량을 지정한다. 다른 컨테이너는 어떤 요청량이나 상한을 지정하지 않는다.
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-4
namespace: qos-example
spec:
containers:
- name: qos-demo-4-ctr-1
image: nginx
resources:
requests:
memory: "200Mi"
- name: qos-demo-4-ctr-2
image: redis
참고로 이 파드는 Burstable QoS 클래스의 기준을 충족한다. 즉, Guaranteed QoS 클래스에 대한 기준을 충족하지 않으며, 해당 컨테이너 중 하나가 메모리 요청량을 갖는다.
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-4.yaml --namespace=qos-example
파드의 상세 정보를 본다.
kubectl get pod qos-demo-4 --namespace=qos-example --output=yaml
출력 결과는 쿠버네티스가 파드에 Burstable QoS 클래스를 부여했음을 보여준다.
spec:
containers:
...
name: qos-demo-4-ctr-1
resources:
requests:
memory: 200Mi
...
name: qos-demo-4-ctr-2
resources: {}
...
status:
qosClass: Burstable
파드를 삭제한다.
kubectl delete pod qos-demo-4 --namespace=qos-example
네임스페이스를 삭제한다.
kubectl delete namespace qos-example
이 페이지는 스토리지의 볼륨을 사용하는 파드를 구성하는 방법을 설명한다.
컨테이너 파일 시스템은 컨테이너가 살아있는 동안만 존재한다. 따라서 컨테이너가 종료되고 재시작할 때, 파일 시스템 변경사항이 손실된다. 컨테이너와 독립적이며 보다 일관된 스토리지를 위해 사용자는 볼륨을 사용할 수 있다. 이것은 레디스(Redis)와 같은 키-값 저장소나 데이터베이스와 같은 스테이트풀 애플리케이션에 매우 중요하다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.이 연습에서는 하나의 컨테이너를 실행하는 파드를 생성한다. 이 파드는 컨테이너가 종료되고, 재시작 하더라도 파드의 수명동안 지속되는 emptyDir 유형의 볼륨이 있다. 파드의 구성 파일은 다음과 같다.
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
volumeMounts:
- name: redis-storage
mountPath: /data/redis
volumes:
- name: redis-storage
emptyDir: {}
파드 생성
kubectl apply -f https://k8s.io/examples/pods/storage/redis.yaml
파드의 컨테이너가 Running 중인지 확인하고, 파드의 변경사항을 지켜본다.
kubectl get pod redis --watch
출력은 이와 유사하다.
NAME READY STATUS RESTARTS AGE
redis 1/1 Running 0 13s
다른 터미널에서 실행 중인 컨테이너의 셸을 획득한다.
kubectl exec -it redis -- /bin/bash
셸에서 /data/redis
로 이동하고, 파일을 생성한다.
root@redis:/data# cd /data/redis/
root@redis:/data/redis# echo Hello > test-file
셸에서 실행 중인 프로세스 목록을 확인한다.
root@redis:/data/redis# apt-get update
root@redis:/data/redis# apt-get install procps
root@redis:/data/redis# ps aux
출력은 이와 유사하다.
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
redis 1 0.1 0.1 33308 3828 ? Ssl 00:46 0:00 redis-server *:6379
root 12 0.0 0.0 20228 3020 ? Ss 00:47 0:00 /bin/bash
root 15 0.0 0.0 17500 2072 ? R+ 00:48 0:00 ps aux
셸에서 Redis 프로세스를 강제종료(kill)한다.
root@redis:/data/redis# kill <pid>
여기서 <pid>
는 Redis 프로세스 ID(PID) 이다.
원래 터미널에서, Redis 파드의 변경을 지켜본다. 결국, 다음과 유사한 것을 보게 될 것이다.
NAME READY STATUS RESTARTS AGE
redis 1/1 Running 0 13s
redis 0/1 Completed 0 6m
redis 1/1 Running 1 6m
이때, 컨테이너는 종료되고 재시작된다. 이는
Redis 파드의
restartPolicy는
Always
이기 때문이다.
재시작된 컨테이너의 셸을 획득한다.
kubectl exec -it redis -- /bin/bash
셸에서 /data/redis
로 이동하고, test-file
이 여전히 존재하는지 확인한다.
root@redis:/data/redis# cd /data/redis/
root@redis:/data/redis# ls
test-file
이 연습을 위해 생성한 파드를 삭제한다.
kubectl delete pod redis
이 페이지는 스토리지에 대해 퍼시스턴트볼륨클레임(PersistentVolumeClaim)을 사용하도록 파드를 설정하는 방법을 보여준다. 과정의 요약은 다음과 같다.
클러스터 관리자로서, 물리적 스토리지와 연결되는 퍼시스턴트볼륨을 생성한다. 볼륨을 특정 파드와 연결하지 않는다.
그 다음 개발자 / 클러스터 사용자의 역할로서, 적합한 퍼시스턴트볼륨에 자동으로 바인딩되는 퍼시스턴트볼륨클레임을 생성한다.
스토리지에 대해 위의 퍼시스턴트볼륨클레임을 사용하는 파드를 생성한다.
사용자는 노드가 단 하나만 있는 쿠버네티스 클러스터가 필요하고, kubectl 커맨드라인 툴이 사용자의 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 만약 사용자가 아직 단일 노드 클러스터를 가지고 있지 않다면, Minikube를 사용하여 클러스터 하나를 생성할 수 있다.
퍼시스턴트 볼륨의 관련 자료에 익숙해지도록 한다.
사용자 클러스터의 단일 노드에 연결되는 셸을 연다. 셸을 여는 방법은
클러스터 설정에 따라 달라진다. 예를 들어 Minikube를 사용하는 경우,
minikube ssh
명령어를 입력하여 노드로 연결되는 셸을 열 수 있다.
해당 노드의 셸에서 /mnt/data
디렉터리를 생성한다.
# 사용자 노드에서 슈퍼유저로 명령을 수행하기 위하여
# "sudo"를 사용한다고 가정한다
sudo mkdir /mnt/data
/mnt/data
디렉터리에서 index.html
파일을 생성한다.
# 이번에도 사용자 노드에서 슈퍼유저로 명령을 수행하기 위하여
# "sudo"를 사용한다고 가정한다
sudo sh -c "echo 'Hello from Kubernetes storage' > /mnt/data/index.html"
sudo
이외의 슈퍼유저 접근 툴을 사용하는 경우,
sudo
를 해당 툴의 이름으로 바꾸면, 동일하게 작업을 수행할 수 있다.index.html
파일이 존재하는지 테스트한다.
cat /mnt/data/index.html
결과는 다음과 같다.
Hello from Kubernetes storage
이제 사용자 노드에서 셸을 종료해도 된다.
이 예제에서, 사용자는 hostPath 퍼시스턴트볼륨을 생성한다. 쿠버네티스는 단일 노드에서의 개발과 테스트를 위해 hostPath를 지원한다. hostPath 퍼시스턴트볼륨은 네트워크로 연결된 스토리지를 모방하기 위해, 노드의 파일이나 디렉터리를 사용한다.
운영 클러스터에서, 사용자가 hostPath를 사용하지는 않는다. 대신, 클러스터 관리자는 Google Compute Engine 영구 디스크, NFS 공유 또는 Amazone Elastic Block Store 볼륨과 같은 네트워크 자원을 프로비저닝한다. 클러스터 관리자는 스토리지클래스(StorageClasses)를 사용하여 동적 프로비저닝을 설정할 수도 있다.
hostPath 퍼시스턴트볼륨의 설정 파일은 아래와 같다.
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
설정 파일에 클러스터 노드의 /mnt/data
에 볼륨이 있다고
지정한다. 또한 설정에서 볼륨 크기를 10 기가바이트로 지정하고 단일 노드가
읽기-쓰기 모드로 볼륨을 마운트할 수 있는 ReadWriteOnce
접근 모드를 지정한다. 여기서는
퍼시스턴트볼륨클레임의 스토리지클래스 이름을
manual
로 정의하며, 퍼시스턴트볼륨클레임의 요청을
이 퍼시스턴트볼륨에 바인딩하는 데 사용한다.
퍼시스턴트볼륨을 생성한다.
kubectl apply -f https://k8s.io/examples/pods/storage/pv-volume.yaml
퍼시스턴트볼륨에 대한 정보를 조회한다.
kubectl get pv task-pv-volume
결과는 퍼시스턴트볼륨의 STATUS
가 Available
임을 보여준다. 이는
아직 퍼시스턴트볼륨클레임이 바인딩되지 않았다는 것을 의미한다.
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 10Gi RWO Retain Available manual 4s
다음 단계는 퍼시스턴트볼륨클레임을 생성하는 단계이다. 파드는 퍼시스턴트볼륨클레임을 사용하여 물리적인 스토리지를 요청한다. 이 예제에서, 사용자는 적어도 하나 이상의 노드에 대해 읽기-쓰기 접근을 지원하며 최소 3 기가바이트의 볼륨을 요청하는 퍼시스턴트볼륨클레임을 생성한다.
퍼시스턴트볼륨클레임에 대한 설정 파일은 다음과 같다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
퍼시스턴트볼륨클레임을 생성한다.
kubectl apply -f https://k8s.io/examples/pods/storage/pv-claim.yaml
사용자가 퍼시스턴트볼륨클레임을 생성한 후에, 쿠버네티스 컨트롤 플레인은 클레임의 요구사항을 만족하는 퍼시스턴트볼륨을 찾는다. 컨트롤 플레인이 동일한 스토리지클래스를 갖는 적절한 퍼시스턴트볼륨을 찾으면, 볼륨에 클레임을 바인딩한다.
퍼시스턴트볼륨을 다시 확인한다.
kubectl get pv task-pv-volume
이제 결과는 STATUS
가 Bound
임을 보여준다.
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 10Gi RWO Retain Bound default/task-pv-claim manual 2m
퍼시스턴트볼륨클레임을 확인한다.
kubectl get pvc task-pv-claim
결과는 퍼시스턴트볼륨클레임이 사용자의 퍼시스턴트볼륨인 task-pv-volume
에
바인딩되어 있음을 보여준다.
NAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGE
task-pv-claim Bound task-pv-volume 10Gi RWO manual 30s
다음 단계는 볼륨으로 퍼시스턴트볼륨클레임을 사용하는 파드를 만드는 단계이다.
파드에 대한 설정 파일은 다음과 같다.
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim
containers:
- name: task-pv-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage
파드의 설정 파일은 퍼시스턴트볼륨클레임을 지정하지만, 퍼시스턴트볼륨을 지정하지는 않는다는 것을 유념하자. 파드의 관점에서 볼때, 클레임은 볼륨이다.
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/pods/storage/pv-pod.yaml
파드의 컨테이너가 실행 중임을 확인한다.
kubectl get pod task-pv-pod
사용자 파드에서 구동되고 있는 컨테이너에 셸로 접근한다.
kubectl exec -it task-pv-pod -- /bin/bash
사용자의 셸에서, nginx가 hostPath 볼륨으로부터 index.html
파일을
제공하는지 확인한다.
# 이전 단계에서 "kubectl exec" 명령을 실행한 root 셸 안에서
# 다음의 3개 명령을 실행해야 한다.
apt update
apt install curl
curl http://localhost/
결과는 hostPath 볼륨에 있는 index.html
파일에 사용자가 작성한 텍스트를
보여준다.
Hello from Kubernetes storage
만약 사용자가 위와 같은 메시지를 확인하면, 파드가 퍼시스턴트볼륨클레임의 스토리지를 사용하도록 성공적으로 설정한 것이다.
파드, 퍼시스턴트볼륨클레임, 퍼시스턴트볼륨을 삭제한다.
kubectl delete pod task-pv-pod
kubectl delete pvc task-pv-claim
kubectl delete pv task-pv-volume
만약 클러스터의 노드에 대한 셸이 열려져 있지 않은 경우, 이전과 동일한 방식으로 새로운 셸을 연다.
사용자 노드의 셸에서, 생성한 파일과 디렉터리를 제거한다.
# 사용자 노드에서 슈퍼유저로 명령을 수행하기 위하여
# "sudo"를 사용한다고 가정한다
sudo rm /mnt/data/index.html
sudo rmdir /mnt/data
이제 사용자 노드에서 셸을 종료해도 된다.
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
- name: test
image: nginx
volumeMounts:
# a mount for site-data
- name: config
mountPath: /usr/share/nginx/html
subPath: html
# another mount for nginx config
- name: config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: config
persistentVolumeClaim:
claimName: test-nfs-claim
하나의 퍼시스턴트볼륨을 nginx 컨테이너의 두 경로에 마운트할 수 있다.
/usr/share/nginx/html
- 정적 웹사이트 용
/etc/nginx/nginx.conf
- 기본 환경 설정 용
그룹 ID(GID)로 설정된 스토리지는 동일한 GID를 사용하는 파드에서만 쓰기 작업을 허용한다. GID가 일치하지 않거나 누락되었을 경우 권한 거부 오류가 발생한다. 사용자와의 조정 필요성을 줄이기 위하여 관리자는 퍼시스턴트 볼륨에 GID로 어노테이션을 달 수 있다. 그 뒤에, 퍼시스턴트볼륨을 사용하는 모든 파드에 대하여 GID가 자동으로 추가된다.
다음과 같이 pv.beta.kubernetes.io/gid
어노테이션을 사용한다.
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
annotations:
pv.beta.kubernetes.io/gid: "1234"
파드가 GID 어노테이션이 있는 퍼시스턴트볼륨을 사용하면, 어노테이션으로 달린 GID가 파드의 보안 컨텍스트에 지정된 GID와 동일한 방식으로 파드의 모든 컨테이너에 적용된다. 파드의 명세 혹은 퍼시스턴트볼륨의 어노테이션으로부터 생성된 모든 GID는, 각 컨테이너에서 실행되는 첫 번째 프로세스에 적용된다.
이 페이지는 프라이빗 컨테이너 레지스트리나 리포지터리로부터 이미지를 받아오기 위해 시크릿(Secret)을 사용하는 파드를 생성하는 방법을 보여준다. 현재 많은 곳에서 프라이빗 레지스트리가 사용되고 있다. 여기서는 예시 레지스트리로 Docker Hub을 사용한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
이 실습을 수행하기 위해, docker
명령줄 도구와
도커 ID 및 비밀번호가 필요하다.
다른 프라이빗 컨테이너 레지스트리를 사용하는 경우, 해당 레지스트리를 위한 명령줄 도구 및 레지스트리 로그인 정보가 필요하다.
노트북에 프라이빗 이미지를 받아오기 위하여 레지스트리 인증을 필수로 수행해야 한다.
docker
도구를 사용하여 도커 허브에 로그인한다. 자세한 정보는
도커 ID 계정의 로그 인 섹션을 참조한다.
docker login
프롬프트가 나타나면, 도커 ID를 입력한 다음, 사용하려는 자격증명(액세스 토큰, 또는 도커 ID의 비밀번호)을 입력한다.
로그인 프로세스를 수행하면 권한 토큰 정보를 가지고 있는 config.json
파일이 생성되거나 업데이트된다. 쿠버네티스가 이 파일을 어떻게 해석하는지 참고한다.
config.json
파일을 확인하자.
cat ~/.docker/config.json
하단과 유사한 결과를 확인할 수 있다.
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "c3R...zE2"
}
}
}
auth
항목이 아닌, 저장소의 이름을 값으로 사용하는 credsStore
항목을 확인할 수 있다.쿠버네티스 클러스터는 프라이빗 이미지를 받아올 때, 컨테이너 레지스트리에 인증하기 위하여
kubernetes.io/dockerconfigjson
타입의 시크릿을 사용한다.
만약 이미 docker login
을 수행하였다면,
이 때 생성된 자격 증명을 쿠버네티스 클러스터로 복사할 수 있다.
kubectl create secret generic regcred \
--from-file=.dockerconfigjson=<path/to/.docker/config.json> \
--type=kubernetes.io/dockerconfigjson
오브젝트에 대한 더 세밀한 제어(새로운 시크릿에 대한 네임스페이스나 레이블을 지정하는 등)가 필요할 경우, 시크릿을 사용자 정의한 후에 저장할 수도 있다. 다음을 확인하자.
.dockerconfigjson
으로 설정한다data[".dockerconfigjson"]
필드에 자르지 않고 한 줄로 이어서 붙여넣는다type
을 kubernetes.io/dockerconfigjson
으로 설정한다예:
apiVersion: v1
kind: Secret
metadata:
name: myregistrykey
namespace: awesomeapps
data:
.dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==
type: kubernetes.io/dockerconfigjson
만약 error: no objects passed to create
메세지가 출력될 경우, base64로 인코딩된 문자열이 유효하지 않음을 의미한다.
또한 Secret "myregistrykey" is invalid: data[.dockerconfigjson]: invalid value ...
메세지가 출력될 경우,
base64로 인코딩된 문자열이 정상적으로 디코딩되었으나, .docker/config.json
파일로 파싱되지 못한 것을 의미한다.
regcred
라는 이름의 시크릿을 생성하자.
kubectl create secret docker-registry regcred --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>
아래의 각 항목에 대한 설명을 참고한다.
<your-registry-server>
은 프라이빗 도커 저장소의 FQDN 주소이다.
도커허브(DockerHub)는 https://index.docker.io/v1/
를 사용한다.<your-name>
은 도커 사용자의 계정이다.<your-pword>
은 도커 사용자의 비밀번호이다.<your-email>
은 도커 사용자의 이메일 주소이다.이를 통해 regcred
라는 시크릿으로 클러스터 내에서 도커 자격 증명을 생성했다.
kubectl
이 구동 중인 동안 사용자의 PC의 다른 사용자들에게
보일 수도 있다.regcred
검증하기방금 생성한 regcred
시크릿의 내용을 확인하기 위하여, YAML 형식으로 시크릿을 확인하자.
kubectl get secret regcred --output=yaml
결과는 다음과 같다.
apiVersion: v1
kind: Secret
metadata:
...
name: regcred
...
data:
.dockerconfigjson: eyJodHRwczovL2luZGV4L ... J0QUl6RTIifX0=
type: kubernetes.io/dockerconfigjson
.dockerconfigjson
필드의 값은 도커 자격 증명의 base64 인코딩 결과이다.
.dockerconfigjson
필드의 값을 확인하기 위하여, 시크릿 데이터를 읽을 수 있는
형식으로 변경한다.
kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode
결과는 다음과 같다.
{"auths":{"your.private.registry.example.com":{"username":"janedoe","password":"xxxxxxxxxxx","email":"jdoe@example.com","auth":"c3R...zE2"}}}
auth
필드의 값을 확인하기 위하여, base64로 인코딩된 데이터를 읽을 수 있는 형식으로 변경한다.
echo "c3R...zE2" | base64 --decode
결과로, 사용자 이름과 비밀번호가 :
로 연결되어 아래와 같이 표현된다.
janedoe:xxxxxxxxxxx
참고로 시크릿 데이터에는 사용자의 로컬에 있는 ~/.docker/config.json
파일과 유사한 인증 토큰이 포함되어 있다.
이를 통해 regcred
라는 시크릿으로 클러스터 내에서 도커 자격 증명을 생성했다.
다음은 regcred
에 있는 도커 자격 증명에 접근해야 하는 예제 파드의 매니페스트이다.
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: private-reg-container
image: <your-private-image>
imagePullSecrets:
- name: regcred
위 파일을 컴퓨터에 다운로드한다.
curl -L -O my-private-reg-pod.yaml https://k8s.io/examples/pods/private-reg-pod.yaml
my-private-reg-pod.yaml
파일 안에서, <your-private-image>
값을 다음과 같은 프라이빗 저장소 안의 이미지 경로로 변경한다.
your.private.registry.example.com/janedoe/jdoe-private:v1
프라이빗 저장소에서 이미지를 받아오기 위하여, 쿠버네티스에서 자격 증명이 필요하다.
구성 파일의 imagePullSecrets
필드를 통해 쿠버네티스가
regcred
라는 시크릿으로부터 자격 증명을 가져올 수 있다.
시크릿을 사용해서 파드를 생성하고, 파드가 실행되는지 확인하자.
kubectl apply -f my-private-reg-pod.yaml
kubectl get pod private-reg
imagePullSecrets
필드에 대해 읽어보기이 문서는 쿠버네티스 클러스터의 특정 노드에 노드 어피니티를 사용해 쿠버네티스 파드를 할당하는 방법을 설명한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
쿠버네티스 서버의 버전은 다음과 같거나 더 높아야 함. 버전: v1.10. 버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.클러스터의 노드를 레이블과 함께 나열하자.
kubectl get nodes --show-labels
결과는 아래와 같다.
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
노드 한 개를 선택하고, 레이블을 추가하자.
kubectl label nodes <your-node-name> disktype=ssd
<your-node-name>
는 선택한 노드의 이름이다.
선택한 노드가 disktype=ssd
레이블을 갖고 있는지 확인하자.
kubectl get nodes --show-labels
결과는 아래와 같다.
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,disktype=ssd,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
위의 결과에서, worker0
노드에 disktype=ssd
레이블이 있는 것을
확인할 수 있다.
이 매니페스트는 disktype: ssd
라는 requiredDuringSchedulingIgnoredDuringExecution
노드 어피니티를 가진 파드를 설명한다.
파드가 disktype=ssd
레이블이 있는 노드에만 스케줄될 것이라는 것을 의미한다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
매니페스트를 적용하여 선택한 노드에 스케줄된 파드를 생성한다.
kubectl apply -f https://k8s.io/examples/pods/pod-nginx-required-affinity.yaml
파드가 선택한 노드에서 실행 중인지 확인하자.
kubectl get pods --output=wide
결과는 아래와 같다.
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
이 매니페스트는 disktype: ssd
라는 preferredDuringSchedulingIgnoredDuringExecution
노드 어피니티를 가진 파드를 설명한다.
파드가 disktype=ssd
레이블이 있는 노드를 선호한다는 것을 의미한다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
매니페스트를 적용하여 선택한 노드에 스케줄된 파드를 생성한다.
kubectl apply -f https://k8s.io/examples/pods/pod-nginx-preferred-affinity.yaml
파드가 선택한 노드에서 실행 중인지 확인하자.
kubectl get pods --output=wide
결과는 아래와 같다.
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
노드 어피니티에 대해 더 알아보기.
이 문서는 쿠버네티스 클러스터의 특정 노드에 쿠버네티스 파드를 할당하는 방법을 설명한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.클러스터의 노드를 레이블과 함께 나열하자.
kubectl get nodes --show-labels
결과는 아래와 같다.
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
노드 한 개를 선택하고, 레이블을 추가하자.
kubectl label nodes <your-node-name> disktype=ssd
<your-node-name>
는 선택한 노드의 이름이다.
선택한 노드가 disktype=ssd
레이블을 갖고 있는지 확인하자.
kubectl get nodes --show-labels
결과는 아래와 같다.
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,disktype=ssd,kubernetes.io/hostname=worker0
worker1 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker1
worker2 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker2
위의 결과에서, worker0
노드에 disktype=ssd
레이블이 있는 것을
확인할 수 있다.
이 파드 구성 파일은 disktype: ssd
라는 선택하는 노드 셀렉터를 가진 파드를
설명한다.
즉, disktype=ssd
레이블이 있는 노드에 파드가 스케줄될 것이라는
것을 의미한다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
구성 파일을 사용해서 선택한 노드로 스케줄되도록 파드를 생성하자.
kubectl apply -f https://k8s.io/examples/pods/pod-nginx.yaml
파드가 선택한 노드에서 실행 중인지 확인하자.
kubectl get pods --output=wide
결과는 아래와 같다.
NAME READY STATUS RESTARTS AGE IP NODE
nginx 1/1 Running 0 13s 10.200.0.4 worker0
nodeName
설정을 통해 특정 노드로 파드를 배포할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
nodeName: foo-node # 특정 노드에 파드 스케줄
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
설정 파일을 사용해 foo-node
노드에 파드를 스케줄되도록 만들어 보자.
이 페이지는 애플리케이션 실행 전에 파드를 초기화하기 위해 어떻게 초기화 컨테이너를 구성해야 하는지 보여준다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.이 연습에서 하나의 애플리케이션 컨테이너와 하나의 초기화 컨테이너를 갖는 파드를 생성한다. 초기화 컨테이너는 애플리케이션 시작 전에 실행을 종료한다.
아래는 해당 파드의 구성 파일이다.
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
# 이 컨테이너들은 파드 초기화 중에 실행된다.
initContainers:
- name: install
image: busybox
command:
- wget
- "-O"
- "/work-dir/index.html"
- http://info.cern.ch
volumeMounts:
- name: workdir
mountPath: "/work-dir"
dnsPolicy: Default
volumes:
- name: workdir
emptyDir: {}
이 구성 파일에서, 파드가 가진 볼륨을 초기화 컨테이너와 애플리케이션 컨테이너가 공유하는 것을 볼 수 있다.
초기화 컨테이너는 공유된 볼륨을
/work-dir
에 마운트하고, 애플리케이션 컨테이너는 공유된 볼륨을
/usr/share/nginx/html
에 마운트한다. 초기화 컨테이너는 다음 명령을 실행 후
종료한다.
wget -O /work-dir/index.html http://info.cern.ch
초기화 컨테이너는 nginx 서버의 루트 디렉터리 내 index.html
파일을
저장한다.
파드를 생성한다.
kubectl apply -f https://k8s.io/examples/pods/init-containers.yaml
nginx 컨테이너가 실행 중인지 확인한다.
kubectl get pod init-demo
출력 결과는 nginx 컨테이너가 실행 중임을 보여준다.
NAME READY STATUS RESTARTS AGE
init-demo 1/1 Running 0 1m
init-demo 파드 내 실행 중인 nginx 컨테이너의 셸을 실행한다.
kubectl exec -it init-demo -- /bin/bash
셸에서 GET 요청을 nginx 서버로 전송한다.
root@nginx:~# apt-get update
root@nginx:~# apt-get install curl
root@nginx:~# curl localhost
출력 결과는 nginx가 초기화 컨테이너에 의해 저장된 웹 페이지를 제공하고 있음을 보여준다.
<html><head></head><body><header>
<title>http://info.cern.ch</title>
</header>
<h1>http://info.cern.ch - home of the first website</h1>
...
<li><a href="http://info.cern.ch/hypertext/WWW/TheProject.html">Browse the first website</a></li>
...
스태틱 파드 는 API 서버 없이 특정 노드에 있는 kubelet 데몬에 의해 직접 관리된다. 컨트롤 플레인에 의해 관리되는 파드(예를 들어 디플로이먼트(Deployment))와는 달리, kubelet 이 각각의 스태틱 파드를 감시한다. (만약 실패할 경우 다시 구동한다.)
스태틱 파드는 항상 특정 노드에 있는 하나의 Kubelet에 매여 있다.
Kubelet 은 각각의 스태틱 파드에 대하여 쿠버네티스 API 서버에서 미러 파드(mirror pod)를 생성하려고 자동으로 시도한다. 즉, 노드에서 구동되는 파드는 API 서버에 의해서 볼 수 있지만, API 서버에서 제어될 수는 없다. 파드 이름에는 노드 호스트 이름 앞에 하이픈을 붙여 접미사로 추가된다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.이 페이지는 파드를 실행하기 위해 CRI-O를 사용하며, 노드에서 Fedora 운영 체제를 구동하고 있다고 가정한다. 다른 배포판이나 쿠버네티스 설치 지침과는 다소 상이할 수 있다.
파일 시스템이 호스팅하는 구성 파일이나 웹이 호스팅하는 구성 파일을 사용하여 스태틱 파드를 구성할 수 있다.
매니페스트는 특정 디렉터리에 있는 JSON 이나 YAML 형식의 표준 파드 정의이다.
kubelet 구성 파일의 staticPodPath: <the directory>
필드를 사용하자.
명시한 디렉터리를 정기적으로 스캔하여, 디렉터리 안의 YAML/JSON 파일이 생성되거나 삭제되었을 때 스태틱 파드를 생성하거나 삭제한다.
Kubelet 이 특정 디렉터리를 스캔할 때 점(.)으로 시작하는 단어를 무시한다는 점을 유의하자.
예를 들어, 다음은 스태틱 파드로 간단한 웹 서버를 구동하는 방법을 보여준다.
스태틱 파드를 실행할 노드를 선택한다. 이 예제에서는 my-model
이다.
ssh my-node1
/etc/kubelet.d
와 같은 디렉터리를 선택하고 웹 서버 파드의 정의를 해당 위치에, 예를 들어 /etc/kubelet.d/static-web.yaml
에 배치한다.
# kubelet 이 동작하고 있는 노드에서 이 명령을 수행한다.
mkdir /etc/kubelet.d/
cat <<EOF >/etc/kubelet.d/static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
role: myrole
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
EOF
노드에서 kubelet 실행 시에 --pod-manifest-path=/etc/kubelet.d/
와 같이 인자를 제공하여 해당 디렉터리를 사용하도록 구성한다. Fedora 의 경우 이 줄을 포함하기 위하여 /etc/kubernetes/kubelet
파일을 다음과 같이 수정한다.
KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --pod-manifest-path=/etc/kubelet.d/"
혹은 kubelet 구성 파일에
staticPodPath: <the directory>
필드를 추가한다.
kubelet을 재시작한다. Fedora의 경우 아래와 같이 수행한다.
# kubelet 이 동작하고 있는 노드에서 이 명령을 수행한다.
systemctl restart kubelet
Kubelet은 --manifest-url=<URL>
의 인수로 지정된 파일을 주기적으로 다운로드하여
해당 파일을 파드의 정의가 포함된 JSON/YAML 파일로 해석한다.
파일시스템이 호스팅 하는 매니페스트 의 작동 방식과
유사하게 kubelet은 스케줄에 맞춰 매니페스트 파일을 다시 가져온다. 스태틱 파드의 목록에
변경된 부분이 있을 경우, kubelet 은 이를 적용한다.
이 방법을 사용하기 위하여 다음을 수행한다.
kubelet 에게 파일의 URL을 전달하기 위하여 YAML 파일을 생성하고 이를 웹 서버에 저장한다.
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
role: myrole
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
선택한 노드에서 --manifest-url=<manifest-url>
을 실행하여 웹 메니페스트를 사용하도록 kubelet을 구성한다. Fedora 의 경우 이 줄을 포함하기 위하여 /etc/kubernetes/kubelet
파일을 수정한다.
KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --manifest-url=<manifest-url>"
Kubelet을 재시작한다. Fedora의 경우 아래와 같이 수행한다.
# kubelet 이 동작하고 있는 노드에서 이 명령을 수행한다.
systemctl restart kubelet
Kubelet 을 시작하면, 정의된 모든 스태틱 파드가 자동으로 시작된다. 스태틱 파드를 정의하고, kubelet을 재시작했으므로, 새로운 스태틱 파드가 이미 실행 중이어야 한다.
(노드에서) 구동되고 있는 (스태틱 파드를 포함한) 컨테이너들을 볼 수 있다.
# kubelet 이 동작하고 있는 노드에서 이 명령을 수행한다.
crictl ps
결과는 다음과 유사하다.
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
129fd7d382018 docker.io/library/nginx@sha256:... 11 minutes ago Running web 0 34533c6729106
crictl
은 이미지 URI와 SHA-256 체크섬을 출력한다. NAME
은 다음과 같을 것이다.
docker.io/library/nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
API 서버에서 미러 파드를 볼 수 있다.
kubectl get pods
NAME READY STATUS RESTARTS AGE
static-web 1/1 Running 0 2m
스태틱 파드에 있는 레이블 은 미러 파드로 전파된다. 셀렉터 등을 통하여 이러한 레이블을 사용할 수 있다.
만약 API 서버로부터 미러 파드를 지우기 위하여 kubectl
을 사용하려 해도,
kubelet 은 스태틱 파드를 지우지 않는다.
kubectl delete pod static-web
pod "static-web" deleted
파드가 여전히 구동 중인 것을 볼 수 있다.
kubectl get pods
NAME READY STATUS RESTARTS AGE
static-web 1/1 Running 0 4s
kubelet 이 구동 중인 노드로 돌아가서 컨테이너를 수동으로 중지할 수 있다. 일정 시간이 지나면, kubelet이 파드를 자동으로 인식하고 다시 시작하는 것을 볼 수 있다.
# kubelet 이 동작하고 있는 노드에서 이 명령을 수행한다.
crictl stop 129fd7d382018 # 예제를 수행하는 사용자의 컨테이너 ID로 변경한다.
sleep 20
crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
89db4553e1eeb docker.io/library/nginx@sha256:... 19 seconds ago Running web 1 34533c6729106
실행 중인 kubelet 은 주기적으로, 설정된 디렉터리(예제에서는 /etc/kubelet.d
)에서 변경 사항을 스캔하고, 이 디렉터리에 새로운 파일이 생성되거나 삭제될 경우, 파드를 생성/삭제 한다.
# 예제를 수행하는 사용자가 파일시스템이 호스팅하는 스태틱 파드 설정을 사용한다고 가정한다.
# kubelet 이 동작하고 있는 노드에서 이 명령을 수행한다.
#
mv /etc/kubelet.d/static-web.yaml /tmp
sleep 20
crictl ps
# 구동 중인 nginx 컨테이너가 없는 것을 확인한다.
mv /tmp/static-web.yaml /etc/kubelet.d/
sleep 20
crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID
f427638871c35 docker.io/library/nginx@sha256:... 19 seconds ago Running web 1 34533c6729106
쿠버네티스 오브젝트는 여러 개의 오브젝트 구성 파일을
디렉터리에 저장하고 필요에 따라 kubectl apply
를
사용하여 재귀적으로 오브젝트를 생성하고 업데이트함으로써 생성, 업데이트 및 삭제할 수 있다.
이 방식은 변경사항을 되돌려 오브젝트 구성 파일에 병합하지 않고
활성 오브젝트에 가해진 기록을 유지한다. kubectl diff
는 또한
apply
가 어떠한 변경사항을 이루어질지에 대한 프리뷰를 제공한다.
kubectl
를 설치한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.kubectl
툴은 세 가지 방식의 오브젝트 관리를 지원한다.
오브젝트 관리 방식의 종류별 장단점에 대한 논의는 쿠버네티스 오브젝트 관리를 참고한다.
선언형 오브젝트 구성은 쿠버네티스 오브젝트 정의와 구성에 대한 확실한 이해가 필요하다. 아직 그렇지 못하다면, 먼저 다음 문서를 읽고 이해한다.
다음은 이 문서에서 사용되는 용어에 대한 정의이다.
kubectl apply
에 구성 파일을 전달하는지에 대해 보여준다. 구성 파일은 일반적으로 Git과 같은, 소스 컨트롤에 저장된다.kubectl apply
를 실행하여 변경사항을 기록한다.기존에 존재하는 것을 제외한, 지정한 디렉터리 내 구성 파일에 의해 정의된 모든 오브젝트를 생성하기 위해 kubectl apply
를
사용한다.
kubectl apply -f <디렉터리>/
이것은 각 오브젝트에 대해 kubectl.kubernetes.io/last-applied-configuration: '{...}'
어노테이션을 설정한다. 해당 어노테이션은 오브젝트를 생성하기 위해 사용했던
오브젝트 구성 파일의 내용을 포함한다.
-R
플래그를 추가한다.다음은 오브젝트 구성 파일에 대한 예시이다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
생성될 오브젝트를 출력하려면 kubectl diff
를 실행한다.
kubectl diff -f https://k8s.io/examples/application/simple_deployment.yaml
diff
는 kube-apiserver
의 활성화가 필요한
서버사이드 dry-run을 사용한다.
diff
는 dry-run 모드에서 서버 측 적용 요청을 수행하므로,
PATCH
, CREATE
, 그리고 UPDATE
권한을 부여해야 한다.
자세한 것은
Dry-Run 인증을 본다.
kubectl apply
를 사용하여 오브젝트를 생성한다.
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
kubectl get
을 사용하여 활성 구성을 출력한다.
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
출력은 kubectl.kubernetes.io/last-applied-configuration
어노테이션이
활성 구성에 기록된 것을 보여주며, 그것은 구성 파일과 일치한다.
kind: Deployment
metadata:
annotations:
# ...
# This is the json representation of simple_deployment.yaml
# It was written by kubectl apply when the object was created
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
또한 오브젝트가 기존에 존재하더라도 디렉터리 내 정의된 모든 오브젝트를 업데이트하기 위해 kubectl apply
를
사용할 수 있다. 이러한 접근방식은 다음을 수행할 수 있게 해준다.
kubectl diff -f <디렉터리>/
kubectl apply -f <디렉터리>/
-R
플래그를 추가한다.다음은 구성 파일의 예시이다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
kubectl apply
를 사용하여 오브젝트를 생성한다.
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
kubectl get
을 사용하여 활성 구성을 출력한다.
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
출력은 kubectl.kubernetes.io/last-applied-configuration
어노테이션이
활성 구성에 기록된 것을 보여주며, 그것은 구성 파일과 일치한다.
kind: Deployment
metadata:
annotations:
# ...
# This is the json representation of simple_deployment.yaml
# It was written by kubectl apply when the object was created
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
kubectl scale
을 사용하여 활성 구성 내 replicas
필드를 직접 업데이트한다.
이는 kubectl apply
를 사용하지 않는다.
kubectl scale deployment/nginx-deployment --replicas=2
kubectl get
을 사용하여 활성 구성을 출력한다.
kubectl get deployment nginx-deployment -o yaml
출력은 replicas
필드가 2로 설정된 것을 보여주며, last-applied-configuration
어노테이션은 replicas
필드를 포함하지 않는다.
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# note that the annotation does not contain replicas
# because it was not updated through apply
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
replicas: 2 # written by scale
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
nginx:1.14.2
에서 nginx:1.16.1
로 이미지를 변경하기 위해 simple_deployment.yaml
구성 파일을 업데이트 하고, minReadySeconds
필드를 삭제한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.1 # update the image
ports:
- containerPort: 80
구성 파일에 이루어진 변경사항을 적용한다.
kubectl diff -f https://k8s.io/examples/application/update_deployment.yaml
kubectl apply -f https://k8s.io/examples/application/update_deployment.yaml
kubectl get
을 사용하여 활성 구성을 출력한다.
kubectl get -f https://k8s.io/examples/application/update_deployment.yaml -o yaml
출력은 활성 구성에 다음의 변경사항을 보여준다.
replicas
필드는 kubectl scale
에 의해 설정된 값 2를 유지한다.image
필드는 nginx:1.14.2
에서 nginx:1.16.1
로 업데이트되었다.last-applied-configuration
어노테이션은 새로운 이미지로 업데이트되었다.minReadySeconds
필드는 지워졌다.last-applied-configuration
어노테이션은 더 이상 minReadySeconds
필드를 포함하지 않는다.apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# The annotation contains the updated image to nginx 1.11.9,
# but does not contain the updated replicas to 2
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
replicas: 2 # Set by `kubectl scale`. Ignored by `kubectl apply`.
# minReadySeconds cleared by `kubectl apply`
# ...
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.16.1 # Set by `kubectl apply`
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
create
와 replace
와 함께 kubectl apply
를
혼합하는 것은 지원하지 않는다. 이는 kubectl apply
가 업데이트 사항을 계산하는데 사용하는
kubectl.kubernetes.io/last-applied-configuration
을 create
와 replace
가
유지하지 하지 않기 때문이다.kubectl apply
에 의해 관리되는 오브젝트를 삭제하는데 2가지 접근 방법이 있다.
kubectl delete -f <파일명>
명령형 커맨드를 사용하여 오브젝트를 수동으로 삭제하는 것이 권장되는 방식인데, 무엇이 삭제되는지에 대해 더 명확하게 나타내므로 사용자가 의도하지 않게 무언가를 삭제할 가능성이 작아지기 때문이다.
kubectl delete -f <파일명>
kubectl apply -f <디렉터리/> --prune -l your=레이블
무엇을 하는지 파악하는 경우에만 이를 사용한다.
kubectl apply --prune
은 알파 상태이며, 후속 릴리스에서는
하위 호환되지 않는 변경 사항이 도입될 수 있다.kubectl delete
에 대한 대안으로, 디렉터리로부터 구성 파일이 삭제된 후에 삭제될 오브젝트를 식별하기 위해 kubectl apply
를 사용할 수 있다.
--prune
을 사용하여 적용하면 일련의 레이블의 집합과 일치하는
모든 오브젝트에 대해API 서버에 쿼리하고, 반환된 활성 오브젝트
구성을 오브젝트 구성 파일에 일치시키려고 시도한다.
오브젝트가 쿼리에 일치하고, 해당 디렉터리 내 구성 파일이 없고
last-applied-configuration
어노테이션이 있는 경우,
삭제된다.
kubectl apply -f <디렉터리/> --prune -l <레이블>
-l <레이블>
로 지정된 레이블 셀렉터에 의해 반환되고 하위 디렉터리에 나타나지 않는 경우,
오브젝트가 의도하지 않게 삭제될 수 있다.활성 오브젝트의 구성을 확인하기 위해 -o yaml
과 함께 kubectl get
을 사용할 수 있다.
kubectl get -f <파일명|url> -o yaml
kubectl apply
가 하나의 오브젝트에 대한 활성 구성을 업데이트할 때,
API 서버에 패치 요청을 보냄으로써 그것을 수행한다.
그 패치는 활성 오브젝트 구성의 특정 필드에 대한 범위의
업데이트로 한정한다. kubectl apply
커맨드는
구성 파일, 활성 구성, 그리고 활성 구성에 저장된
last-applied-configuration
어노테이션을 사용하여 이 패치 요청을 계산한다.
kubectl apply
명령은
kubectl.kubernetes.io/last-applied-configuration
어노테이션에 구성 파일의 내용을 기록한다.
이것은 구성 파일로부터 제거되었고 활성 구성으로부터 지워질 필요가 있는
필드를 확인하는 데 사용된다. 다음은 어떤 필드가 삭제 또는 설정돼야 하는지
계산하기 위해 사용되는 단계이다.
last-applied-configuration
내 존재하고 구성 파일로부터 유실된 필드이다.다음은 예시이다. 디플로이먼트 오브젝트에 대한 구성 파일이라고 가정한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.1 # update the image
ports:
- containerPort: 80
또한, 이것은 동일한 디플로이먼트 오브젝트에 대한 활성 구성이라고 가정한다.
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# note that the annotation does not contain replicas
# because it was not updated through apply
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
replicas: 2 # written by scale
# ...
minReadySeconds: 5
selector:
matchLabels:
# ...
app: nginx
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
# ...
name: nginx
ports:
- containerPort: 80
# ...
다음은 kubectl apply
에 의해 수행될 병합 계산이다.
last-applied-configuration
으로부터 값을 읽어
구성 파일의 값과 비교하여 삭제할 필드를
계산한다.
last-applied-configuration
에 보이는 것과는 무관하게
로컬의 오브젝트 구성 파일 내 null이라고 명시적으로 설정된 필드를 지운다.
이 예시에서, minReadySeconds
은
last-applied-configuration
어노테이션 내 나타나지만, 구성 파일 내에는 보여지지 않는다.
조치: 활성 구성으로부터 minReadySeconds
을 지운다.image
값은 활성 구성 내 값과 불일치한다.
조치: 활성 구성 내 image
값을 설정한다.last-applied-configuration
어노테이션을 설정한다.다음은 병합의 결과인 활성 구성이다.
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# ...
# The annotation contains the updated image to nginx 1.11.9,
# but does not contain the updated replicas to 2
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}
# ...
spec:
selector:
matchLabels:
# ...
app: nginx
replicas: 2 # Set by `kubectl scale`. Ignored by `kubectl apply`.
# minReadySeconds cleared by `kubectl apply`
# ...
template:
metadata:
# ...
labels:
app: nginx
spec:
containers:
- image: nginx:1.16.1 # Set by `kubectl apply`
# ...
name: nginx
ports:
- containerPort: 80
# ...
# ...
# ...
# ...
구성 파일 내 특정 필드가 필드의 타입에 따라 어떻게 활성 구성과 함께 병합되는가. 여러 가지 필드 타입이 있다.
기본(primitives): 문자열, 숫자 또는 불리언 타입의 필드.
예를 들어, image
와 replicas
는 기본 필드다. 조치: 교체.
맵, 또한 오브젝트 라 칭함: 맵 타입 또는 서브필드를 포함하는 복합 타입의 필드. 예를 들어, 레이블
,
어노테이션
,스펙
및 메타데이터
는 모두 맵이다. 조치: 구성요소 또는 서브필드 병합.
리스트: 기본타입 또는 맵이 될 수 있는 아이템의 리스트를 포함하는 필드.
예를 들어, 컨테이너
, 포트
, 그리고 args
는 리스트다. 조치: 다양함.
kubectl apply
가 맵 또는 리스트 필드를 업데이트하는 경우,
일반적으로 전체 필드를 교체하는 대신, 개별 부 구성요소를 업데이트한다,
예를 들어, 디플로이먼트에 대한 spec
을 병합할 경우, 전체 spec
이
교체되지 않는다. 대신 replicas
와 같은 spec
의 서브필드가
비교되고 병합된다.
기본 필드는 교체되거나 지워진다.
-
는 값이 사용되지 않기 때문에 "해당 없음"으로 사용된다.Field in object configuration file | Field in live object configuration | Field in last-applied-configuration | Action |
---|---|---|---|
Yes | Yes | - | 구성 파일 값 활성으로 설정. |
Yes | No | - | 활성을 로컬 구성으로 설정. |
No | - | Yes | 활성 구성으로부터 지움. |
No | - | No | 아무것도 안함. 활성값 유지. |
맵을 요청하는 필드는 서브필드의 각각 또는 맵의 구성요소를 비교함으로써 병합된다.
-
는 값이 사용되지 않기 때문에 "해당 없음"으로 사용된다.Key in object configuration file | Key in live object configuration | Field in last-applied-configuration | Action |
---|---|---|---|
Yes | Yes | - | 서브필드 값 비교. |
Yes | No | - | 활성을 로컬 구성으로 설정. |
No | - | Yes | 활성 구성으로부터 삭제. |
No | - | No | 아무것도 안함. 활성값 유지. |
리스트에 대한 변경사항을 병합하는 것은 세 가지 전략 중 하나를 사용한다.
전략에 대한 선택은 필드별로 이루어진다.
기초 필드와 동일한 리스트로 취급한다. 전체 리스트를 교체 또는 삭제한다. 이것은 순서를 유지한다.
예시: 파드 내 컨테이너의 args
필드를 업데이트하기 위해 kubectl apply
를 사용한다.
이것은 활성 구성 내 args
의 값을 구성 파일 내 값으로 설정한다.
활성 구성에 추가했던 이전의 모든 args
구성요소들은 유실된다.
구성 파일 내 정의한 args
구성요소의 순서는
활성 구성 내 유지된다.
# last-applied-configuration value
args: ["a", "b"]
# configuration file value
args: ["a", "c"]
# live configuration
args: ["a", "b", "d"]
# result after merge
args: ["a", "c"]
설명: 병합은 새로운 리스트 값으로 구성 파일 값을 사용했다.
리스트를 맵으로 취급하고 각 구성요소의 특정 필드를 키로 취급한다. 개별 구성요소를 추가, 삭제, 또는 업데이트 한다. 이것은 순서를 보존하지 않는다.
이 병합 전략은 각 필드에 patchMergeKey
라 칭하는 특별한 태그를 사용한다.
patchMergeKey
는 쿠버네티스 소스 코드:
types.go
의 각 필드에 대해 정의한다. 맵 리스트를 병합할 때, 주어진 구성요소에 대한 patchMergeKey
로
지정한 필드는 해당 구성요소에 대한 맵키와 같이 사용된다.
예시: kubectl apply
를 사용하여 PodSpec에 대한 containers
필드를 업데이트한다.
이렇게 하면 각 구성요소가
name
별로 키로 되어 있는 맵인 것처럼 리스트를 병합한다.
# last-applied-configuration value
containers:
- name: nginx
image: nginx:1.10
- name: nginx-helper-a # key: nginx-helper-a; will be deleted in result
image: helper:1.3
- name: nginx-helper-b # key: nginx-helper-b; will be retained
image: helper:1.3
# configuration file value
containers:
- name: nginx
image: nginx:1.10
- name: nginx-helper-b
image: helper:1.3
- name: nginx-helper-c # key: nginx-helper-c; will be added in result
image: helper:1.3
# live configuration
containers:
- name: nginx
image: nginx:1.10
- name: nginx-helper-a
image: helper:1.3
- name: nginx-helper-b
image: helper:1.3
args: ["run"] # Field will be retained
- name: nginx-helper-d # key: nginx-helper-d; will be retained
image: helper:1.3
# result after merge
containers:
- name: nginx
image: nginx:1.10
# Element nginx-helper-a was deleted
- name: nginx-helper-b
image: helper:1.3
args: ["run"] # Field was retained
- name: nginx-helper-c # Element was added
image: helper:1.3
- name: nginx-helper-d # Element was ignored
image: helper:1.3
설명:
args
에kubectl apply
는args
가 없음) 활성 구성에patchMergeKey
필드 값(이름)이 둘 다 같았기 때문이다..쿠버네티스 1.5로부터 기초 구성요소 병합하기는 지원되지 않는다.
patchStrategy
태그에 의해 제어된다.
타입 필드에 대해 patchStrategy
가 지정되지 않으면,
리스트는 대체된다.오브젝트가 생성될 때 값이 지정되지 않는 경우, API 서버는 활성 구성 내 특정 필드를 기본값으로 설정한다.
다음은 디플로이먼트에 대한 구성 파일이다. 파일에는 strategy
가 지정되지 않았다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
kubectl apply
를 사용하여 오브젝트를 생성한다.
kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml
kubectl get
을 사용하여 활성 구성을 출력한다.
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
출력은 API 서버가 활성 구성 내 여러 필드를 기본값으로 설정한 것을 보여준다. 이 필드들은 구성 파일에 지정되지 않았다.
apiVersion: apps/v1
kind: Deployment
# ...
spec:
selector:
matchLabels:
app: nginx
minReadySeconds: 5
replicas: 1 # defaulted by apiserver
strategy:
rollingUpdate: # defaulted by apiserver - derived from strategy.type
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate # defaulted by apiserver
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:1.14.2
imagePullPolicy: IfNotPresent # defaulted by apiserver
name: nginx
ports:
- containerPort: 80
protocol: TCP # defaulted by apiserver
resources: {} # defaulted by apiserver
terminationMessagePath: /dev/termination-log # defaulted by apiserver
dnsPolicy: ClusterFirst # defaulted by apiserver
restartPolicy: Always # defaulted by apiserver
securityContext: {} # defaulted by apiserver
terminationGracePeriodSeconds: 30 # defaulted by apiserver
# ...
패치 요청에서, 패치 요청의 부분으로서 명시적으로 지워지지 않은 경우 기본 처리된 필드는 다시 기본으로 설정되지 않는다. 이것은 다른 필드에 대한 값에 따라 기본 처리된 필드에 대해 예상하지 못한 동작을 유발할 수 있다. 다른 필드가 나중에 변경되면, 그로부터 기본 처리된 것이 명시적으로 지워지지 않은 한 업데이트되지 않을 것이다.
이러한 사유로, 의도한 값이 서버의 기본값과 일치하더라도, 서버에 의해 기본 처리된 특정 필드는 구성 파일 내 명시적으로 정의할 것을 권고한다. 이렇게 하면 서버에 의해 다시 기본 처리되지 않게 될 충돌하는 값을 보다 쉽게 인식할 수 있도록 해준다.
Example:
# last-applied-configuration
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# configuration file
spec:
strategy:
type: Recreate # updated value
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# live configuration
spec:
strategy:
type: RollingUpdate # defaulted value
rollingUpdate: # defaulted value derived from type
maxSurge : 1
maxUnavailable: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# result after merge - ERROR!
spec:
strategy:
type: Recreate # updated value: incompatible with rollingUpdate
rollingUpdate: # defaulted value: incompatible with "type: Recreate"
maxSurge : 1
maxUnavailable: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
설명:
strategy.type
을 정의하지 않고 디플로이먼트를 생성한다.strategy.type
을 RollingUpdate
로 기본 설정하고
strategy.rollingUpdate
값을 기본 값으로 처리한다.strategy.type
를 Recreate
로 변경한다.
서버에서 해당 값이 삭제될 거라 예상하지만 strategy.rollingUpdate
값은 기본값으로 남아 있다.strategy.rollingUpdate
값이 처음에 구성 파일에서 지정되었다면,
이것을 삭제해야 한다는 것이 더 분명했을 것이다.strategy.rollingUpdate
가 지워지지 않았기 때문에 적용은 실패한다.
strategy.rollingupdate
필드는 Recreate
의 strategy.type
으로 정의될 수 없다.권고: 이들 필드는 오브젝트 구성 파일 내 명시적으로 정의돼야 한다.
구성 파일 내 나타나지 않는 필드는 그 값을
null
로 설정하고 나서 구성 파일을 적용함으로써 지워질 수 있다.
서버가 기본 값을 할당했던 필드에 대해서, 이는 다시 기본 값을
할당하도록 한다.
개별 오브젝트 필드를 변경시키는 데 사용해야 하는 유일한 방법은 다음과 같다.
kubectl apply
를 사용한다.kubectl scale
을 사용한다.구성 파일에 필드를 추가한다. 해당 필드의 경우
kubectl apply
를 거치지 않는 활성 구성에 대해 직접 업데이트를 적용하지 않는다.
쿠버네티스 1.5로부터 구성 파일에서 명령형 작성자로 소유권을 변경하는데 수동 단계 필요하다.
kubectl.kubernetes.io/last-applied-configuration
어노테이션에서 필드를 제거한다.쿠버네티스 오브젝트는 한 번에 오직 하나의 방법을 사용하여 관리돼야 한다. 하나의 방법에서 다른 방법으로 전환하는 것은 가능하나, 수동 프로세스이다.
명령형 커맨드 관리에서 오브젝트 구성으로 이전하는 것은 여러 수동 단계를 포함한다.
활성 오브젝트를 로컬 구성 파일로 내보낸다.
kubectl get <종류>/<이름> -o yaml > <종류>_<이름>.yaml
구성 파일에서 수동으로 status
필드를 제거한다.
kubectl apply
구성 파일에 존재한다고 하더라도 상태 필드가 업데이트되지 않기 때문에,
이 단계는 선택적이다.오브젝트의 kubectl.kubernetes.io/last-applied-configuration
어노테이션을 설정한다.
kubectl replace --save-config -f <종류>_<이름>.yaml
오직 오브젝트를 관리하기 위해 kubectl apply
를 사용하도록 프로세스를 변경한다.
오브젝트의 kubectl.kubernetes.io/last-applied-configuration
어노테이션을 설정한다.
kubectl replace --save-config -f <종류>_<이름>.yaml
오직 오브젝트를 관리하기 위해 kubectl apply
를 사용하도록 프로세스를 변경한다.
권고되는 접근 방법은 다른 의미론적 의미를 가지지 않고 컨트롤러에 의해서만 사용되는 단일, 불변의 파드템플릿 레이블을 정의하는 것이다.
예시:
selector:
matchLabels:
controller-selector: "apps/v1/deployment/nginx"
template:
metadata:
labels:
controller-selector: "apps/v1/deployment/nginx"
Kustomize는 kustomization 파일을 통해 쿠버네티스 오브젝트를 사용자가 원하는 대로 변경하는(customize) 독립형 도구이다.
1.14 이후로, kubectl도 kustomization 파일을 사용한 쿠버네티스 오브젝트의 관리를 지원한다. kustomization 파일을 포함하는 디렉터리 내의 리소스를 보려면 다음 명령어를 실행한다.
kubectl kustomize <kustomization_directory>
이 리소스를 적용하려면 kubectl apply
를 --kustomize
또는 -k
플래그와 함께 실행한다.
kubectl apply -k <kustomization_directory>
kubectl
을 설치한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.Kustomize는 쿠버네티스 구성을 사용자 정의화하는 도구이다. 이는 애플리케이션 구성 파일을 관리하기 위해 다음 기능들을 가진다.
컨피그맵과 시크릿은 파드와 같은 다른 쿠버네티스 오브젝트에서 사용되는 설정이나 민감한 데이터를 가지고 있다. 컨피그맵이나 시크릿의 실질적인 소스는 일반적으로 .properties
파일이나 ssh key 파일과 같은 것들은 클러스터 외부에 있다.
Kustomize는 시크릿과 컨피그맵을 파일이나 문자열에서 생성하는 secretGenerator
와 configMapGenerator
를 가지고 있다.
파일에서 컨피그맵을 생성하려면 configMapGenerator
내의 files
리스트에 항목을 추가한다. 다음은 하나의 .properties
파일에서 데이터 항목으로 컨피그맵을 생성하는 예제이다.
# application.properties 파일을 생성
cat <<EOF >application.properties
FOO=Bar
EOF
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-1
files:
- application.properties
EOF
생성된 컨피그맵은 다음 명령어로 검사할 수 있다.
kubectl kustomize ./
생성된 컨피그맵은 다음과 같다.
apiVersion: v1
data:
application.properties: |
FOO=Bar
kind: ConfigMap
metadata:
name: example-configmap-1-8mbdf7882g
env 파일에서 컨피그맵을 생성하려면, configMapGenerator
의 envs
리스트에 항목을 추가한다. =
및 값을 생략하여 로컬 환경 변수로부터 값을 설정할 수도 있다.
다음은 .env
파일의 데이터 항목으로 컨피그맵을 생성하는 예시를 보여준다.
# .env 파일 생성
# BAZ 에는 로컬 환경 변수 $BAZ 의 값이 입력될 것이다
cat <<EOF >.env
FOO=Bar
BAZ
EOF
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-1
envs:
- .env
EOF
생성된 컨피그맵은 다음 명령어로 검사할 수 있다.
BAZ=Qux kubectl kustomize ./
생성된 컨피그맵은 다음과 같다.
apiVersion: v1
data:
BAZ: Qux
FOO: Bar
kind: ConfigMap
metadata:
name: example-configmap-1-892ghb99c8
.env
파일의 각 변수는 생성한 컨피그맵에서 분리된 키가 된다. .properties
라는 이름의 파일을 내장하는 이전 예시(그리고 모든 항목들)는 단일 키를 위한 값이므로 이 예시와는 다르다.컨피그맵은 문자로된 키-값 쌍들로도 생성할 수 있다. 문자로된 키-값 쌍에서 컨피그맵을 생성하려면, configMapGenerator 내의 literals
리스트에 항목을 추가한다. 다음은 키-값 쌍을 데이터 항목으로 받는 컨피그맵을 생성하는 예제이다.
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-2
literals:
- FOO=Bar
EOF
생성된 컨피그맵은 다음 명령어로 확인할 수 있다.
kubectl kustomize ./
생성된 컨피그맵은 다음과 같다.
apiVersion: v1
data:
FOO: Bar
kind: ConfigMap
metadata:
name: example-configmap-2-g2hdhfc6tk
디플로이먼트에서 생성된 컨피그맵을 사용하기 위해서는, configMapGenerator의 이름을 참조한다. Kustomize는 자동으로 해당 이름을 생성된 이름으로 교체할 것이다.
다음은 생성된 컨피그맵을 사용하는 디플로이먼트의 예시다.
# application.properties 파일을 생성한다.
cat <<EOF >application.properties
FOO=Bar
EOF
cat <<EOF >deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app
volumeMounts:
- name: config
mountPath: /config
volumes:
- name: config
configMap:
name: example-configmap-1
EOF
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
configMapGenerator:
- name: example-configmap-1
files:
- application.properties
EOF
컨피그맵과 디플로이먼트를 생성한다.
kubectl kustomize ./
생성된 디플로이먼트는 이름을 통해서 생성된 컨피그맵을 참조한다.
apiVersion: v1
data:
application.properties: |
FOO=Bar
kind: ConfigMap
metadata:
name: example-configmap-1-g4hk9g2ff8
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-app
name: my-app
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- image: my-app
name: app
volumeMounts:
- mountPath: /config
name: config
volumes:
- configMap:
name: example-configmap-1-g4hk9g2ff8
name: config
파일 또는 문자로된 키-값 쌍들로 시크릿을 생성할 수 있다. 파일에서 시크릿을 생성하려면 secretGenerator
내의 files
리스트에 항목을 추가한다. 다음은 파일을 데이터 항목으로 받는 시크릿을 생성하는 예제이다.
# password.txt 파일을 생성
cat <<EOF >./password.txt
username=admin
password=secret
EOF
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: example-secret-1
files:
- password.txt
EOF
생성된 시크릿은 다음과 같다.
apiVersion: v1
data:
password.txt: dXNlcm5hbWU9YWRtaW4KcGFzc3dvcmQ9c2VjcmV0Cg==
kind: Secret
metadata:
name: example-secret-1-t2kt65hgtb
type: Opaque
문자로된 키-값 쌍으로 시크릿을 생성하려면, secretGenerator
내의 literals
리스트에 항목을 추가한다. 다음은 키-값 쌍을 데이터 항목으로 받는 시크릿을 생성하는 예제이다.
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: example-secret-2
literals:
- username=admin
- password=secret
EOF
생성된 시크릿은 다음과 같다.
apiVersion: v1
data:
password: c2VjcmV0
username: YWRtaW4=
kind: Secret
metadata:
name: example-secret-2-t52t6g96d8
type: Opaque
컨피그맵과 유사하게, 생성된 시크릿도 secretGenerator의 이름을 참조함으로써 디플로이먼트에서 사용될 수 있다.
# password.txt 파일을 생성한다.
cat <<EOF >./password.txt
username=admin
password=secret
EOF
cat <<EOF >deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app
volumeMounts:
- name: password
mountPath: /secrets
volumes:
- name: password
secret:
secretName: example-secret-1
EOF
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
secretGenerator:
- name: example-secret-1
files:
- password.txt
EOF
생성된 컨피그맵과 시크릿은 콘텐츠 해시 접미사가 추가된다. 이는 콘텐츠가 변경될 때 새로운 컨피그맵 이나 시크릿이 생성되는 것을 보장한다. 접미사를 추가하는 동작을 비활성화하는 방법으로 generatorOptions
를 사용할 수 있다. 그밖에, 생성된 컨피그맵과 시크릿에 교차 편집 옵션들을 지정해주는 것도 가능하다.
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-3
literals:
- FOO=Bar
generatorOptions:
disableNameSuffixHash: true
labels:
type: generated
annotations:
note: generated
EOF
생성된 컨피그맵을 보려면 kubectl kustomize ./
를 실행한다.
apiVersion: v1
data:
FOO: Bar
kind: ConfigMap
metadata:
annotations:
note: generated
labels:
type: generated
name: example-configmap-3
프로젝트 내 모든 쿠버네티스 리소스에 교차 편집 필드를 설정하는 것은 꽤나 일반적이다. 교차 편집 필드를 설정하는 몇 가지 사용 사례는 다음과 같다.
다음은 예제이다.
# deployment.yaml을 생성
cat <<EOF >./deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
EOF
cat <<EOF >./kustomization.yaml
namespace: my-namespace
namePrefix: dev-
nameSuffix: "-001"
commonLabels:
app: bingo
commonAnnotations:
oncallPager: 800-555-1212
resources:
- deployment.yaml
EOF
이 필드들이 디플로이먼트 리소스에 모두 설정되었는지 보려면 kubectl kustomize ./
를 실행한다.
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
oncallPager: 800-555-1212
labels:
app: bingo
name: dev-nginx-deployment-001
namespace: my-namespace
spec:
selector:
matchLabels:
app: bingo
template:
metadata:
annotations:
oncallPager: 800-555-1212
labels:
app: bingo
spec:
containers:
- image: nginx
name: nginx
프로젝트 내 리소스의 집합을 구성하여 이들을 동일한 파일이나 디렉터리 내에서 관리하는 것은 일반적이다. Kustomize는 서로 다른 파일들로 리소스를 구성하고 패치나 다른 사용자 정의를 이들에 적용하는 것을 제공한다.
Kustomize는 서로 다른 리소스들의 구성을 지원한다. kustomization.yaml
파일 내 resources
필드는 구성 내에 포함하려는 리소스들의 리스트를 정의한다. resources
리스트 내에 리소스의 구성 파일의 경로를 설정한다.
다음 예제는 디플로이먼트와 서비스로 구성된 NGINX 애플리케이션이다.
# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# service.yaml 파일 생성
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
EOF
# 이들을 구성하는 kustomization.yaml 생성
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF
kubectl kustomize ./
의 리소스에는 디플로이먼트와 서비스 오브젝트가 모두 포함되어 있다.
패치는 리소스에 다른 사용자 정의를 적용하는 데 사용할 수 있다. Kustomize는
patchesStrategicMerge
와 patchesJson6902
를 통해 서로 다른 패치 메커니즘을 지원한다. patchesStrategicMerge
는 파일 경로들의 리스트이다. 각각의 파일은 전략적 병합 패치로 분석될 수 있어야 한다. 패치 내부의 네임은 반드시 이미 읽혀진 리소스 네임과 일치해야 한다. 한 가지 일을 하는 작은 패치가 권장된다. 예를 들기 위해 디플로이먼트 레플리카 숫자를 증가시키는 하나의 패치와 메모리 상한을 설정하는 다른 패치를 생성한다.
# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# increase_replicas.yaml 패치 생성
cat <<EOF > increase_replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 3
EOF
# 다른 패치로 set_memory.yaml 생성
cat <<EOF > set_memory.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
template:
spec:
containers:
- name: my-nginx
resources:
limits:
memory: 512Mi
EOF
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
patchesStrategicMerge:
- increase_replicas.yaml
- set_memory.yaml
EOF
디플로이먼트를 보려면 kubectl kustomize ./
를 실행한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 3
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- image: nginx
name: my-nginx
ports:
- containerPort: 80
resources:
limits:
memory: 512Mi
모든 리소스 또는 필드가 전략적 병합 패치를 지원하는 것은 아니다. 임의의 리소스 내 임의의 필드의 수정을 지원하기 위해,
Kustomize는 patchesJson6902
를 통한 JSON 패치 적용을 제공한다.
Json 패치의 정확한 리소스를 찾기 위해, 해당 리소스의 group, version, kind, name이
kustomization.yaml
내에 명시될 필요가 있다. 예를 들면, patchesJson6902
를 통해
디플로이먼트 오브젝트의 레플리카 개수를 증가시킬 수 있다.
# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# json 패치 생성
cat <<EOF > patch.yaml
- op: replace
path: /spec/replicas
value: 3
EOF
# kustomization.yaml 생성
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: my-nginx
path: patch.yaml
EOF
kubectl kustomize ./
를 실행하여 replicas
필드가 갱신되었는지 확인한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 3
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- image: nginx
name: my-nginx
ports:
- containerPort: 80
패치 기능에 추가로 Kustomize는 패치를 생성하지 않고 컨테이너 이미지를 사용자 정의하거나 다른 오브젝트의 필드 값을 컨테이너에 주입하는
기능도 제공한다. 예를 들어 kustomization.yaml
의 images
필드에 신규 이미지를 지정하여 컨테이너에서 사용되는 이미지를 변경할 수 있다.
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
images:
- name: nginx
newName: my.image.registry/nginx
newTag: 1.4.0
EOF
사용된 이미지가 갱신되었는지 확인하려면 kubectl kustomize ./
를 실행한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 2
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- image: my.image.registry/nginx:1.4.0
name: my-nginx
ports:
- containerPort: 80
가끔, 파드 내에서 실행되는 애플리케이션이 다른 오브젝트의 설정 값을 사용해야 할 수도 있다. 예를 들어,
디플로이먼트 오브젝트의 파드는 Env 또는 커맨드 인수로 해당 서비스 네임을 읽어야 한다고 하자.
kustomization.yaml
파일에 namePrefix
또는 nameSuffix
가 추가되면 서비스 네임이 변경될 수 있다.
커맨드 인수 내에 서비스 네임을 하드 코딩하는 것을 권장하지 않는다. 이 용도에서 Kustomize는 vars
를 통해 containers에 서비스 네임을 삽입할 수 있다.
# deployment.yaml 파일 생성(문서 구분 기호를 따옴표로 감쌈)
cat <<'EOF' > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
command: ["start", "--host", "$(MY_SERVICE_NAME)"]
EOF
# service.yaml 파일 생성
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
EOF
cat <<EOF >./kustomization.yaml
namePrefix: dev-
nameSuffix: "-001"
resources:
- deployment.yaml
- service.yaml
vars:
- name: MY_SERVICE_NAME
objref:
kind: Service
name: my-nginx
apiVersion: v1
EOF
kubectl kustomize ./
를 실행하면 dev-my-nginx-001
로 컨테이너에 삽입된 서비스 네임을 볼 수 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: dev-my-nginx-001
spec:
replicas: 2
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- command:
- start
- --host
- dev-my-nginx-001
image: nginx
name: my-nginx
Kustomize는 base 와 overlay 의 개념을 가지고 있다. base 는 kustomization.yaml
과 함께 사용되는 디렉터리다. 이는
사용자 정의와 관련된 리소스들의 집합을 포함한다. kustomization.yaml
의 내부에 표시되는 base는 로컬 디렉터리이거나 원격 리포지터리의 디렉터리가
될 수 있다. overlay 는 kustomization.yaml
이 있는 디렉터리로
다른 kustomization 디렉터리들을 bases
로 참조한다. base 는 overlay에 대해서 알지 못하며 여러 overlay들에서 사용될 수 있다.
한 overlay는 다수의 base들을 가질 수 있고, base들에서 모든 리소스를 구성할 수 있으며,
이들의 위에 사용자 정의도 가질 수 있다.
다음은 base에 대한 예이다.
# base를 가지는 디렉터리 생성
mkdir base
# base/deployment.yaml 생성
cat <<EOF > base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
EOF
# base/service.yaml 파일 생성
cat <<EOF > base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
EOF
# base/kustomization.yaml 생성
cat <<EOF > base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF
이 base는 다수의 overlay에서 사용될 수 있다. 다른 namePrefix
또는 다른 교차 편집 필드들을
서로 다른 overlay에 추가할 수 있다. 다음 예제는 동일한 base를 사용하는 두 overlay들이다.
mkdir dev
cat <<EOF > dev/kustomization.yaml
bases:
- ../base
namePrefix: dev-
EOF
mkdir prod
cat <<EOF > prod/kustomization.yaml
bases:
- ../base
namePrefix: prod-
EOF
kustomization.yaml
에서 관리되는 리소스를 인식하려면 kubectl
명령어에 --kustomize
나 -k
를 사용한다.
-k
는 다음과 같이 kustomization 디렉터리를 가리키고 있어야 한다는 것을 주의한다.
kubectl apply -k <kustomization directory>/
다음 kustomization.yaml
이 주어지고,
# deployment.yaml 파일 생성
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
EOF
# kustomization.yaml 생성
cat <<EOF >./kustomization.yaml
namePrefix: dev-
commonLabels:
app: my-nginx
resources:
- deployment.yaml
EOF
디플로이먼트 오브젝트 dev-my-nginx
를 적용하려면 다음 명령어를 실행한다.
> kubectl apply -k ./
deployment.apps/dev-my-nginx created
디플로이먼트 오브젝트 dev-my-nginx
를 보려면 다음 명령어들 중에 하나를 실행한다.
kubectl get -k ./
kubectl describe -k ./
다음 명령을 실행해서 디플로이먼트 오브젝트 dev-my-nginx
를 매니페스트가 적용된 경우의 클러스터 상태와 비교한다.
kubectl diff -k ./
디플로이먼트 오브젝트 dev-my-nginx
를 삭제하려면 다음 명령어를 실행한다.
> kubectl delete -k ./
deployment.apps "dev-my-nginx" deleted
필드 | 유형 | 설명 |
---|---|---|
namespace | string | 모든 리소스에 네임스페이스 추가 |
namePrefix | string | 모든 리소스 네임에 이 필드의 값이 접두사로 추가된다 |
nameSuffix | string | 모든 리소스 네임에 이 필드의 값이 접미사로 추가된다 |
commonLabels | map[string]string | 모든 리소스와 셀렉터에 추가될 레이블 |
commonAnnotations | map[string]string | 모든 리소스에 추가될 어노테이션 |
resources | []string | 이 리스트 내 각각의 항목은 반드시 존재하는 리소스 구성 파일로 해석되어야 한다. |
configMapGenerator | []ConfigMapArgs | 이 리스트의 각 항목은 컨피그맵을 생성한다. |
secretGenerator | []SecretArgs | 이 리스트의 각 항목은 시크릿을 생성한다. |
generatorOptions | GeneratorOptions | 모든 컨피그맵 및 시크릿 생성자(generator)의 동작을 수정한다. |
bases | []string | 이 리스트 내 각각의 항목은 kustomization.yaml 파일을 가지는 디렉터리로 해석되어야 한다. |
patchesStrategicMerge | []string | 이 리스트 내 각각의 항목은 쿠버네티스 오브젝트의 전략적 병합 패치로 해석되어야 한다. |
patchesJson6902 | []Patch | 이 리스트 내 각각의 항목은 쿠버네티스 오브젝트와 Json 패치로 해석되어야 한다. |
vars | []Var | 각각의 항목은 한 리소스의 필드에서 텍스트를 캡쳐한다. |
images | []Image | 각각의 항목은 패치를 생성하지 않고 하나의 이미지에 대한 name, tags 그리고/또는 digest를 수정한다. |
configurations | []string | 이 리스트 내 각각의 항목은 Kustomize 변환 설정을 포함하는 파일로 해석되어야 한다. |
crds | []string | 이 리스트 내 각각의 항목은 쿠버네티스 타입에 대한 OpenAPI 정의 파일로 해석되어야 한다. |
쿠버네티스 오브젝트는 kubectl
커맨드 라인 툴 속에 내장된 명령형 커맨드를 이용함으로써
바로 신속하게 생성, 업데이트 및 삭제할 수 있다. 이 문서는 어떻게 커맨드가 구성되어 있으며,
이를 사용하여 활성 오브젝트를 어떻게 관리하는 지에 대해 설명한다.
kubectl
을 설치한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.kubectl
툴은 3가지 종류의 오브젝트 관리를 지원한다.
각 종류별 오브젝트 관리의 장점과 단점에 대한 논의는 쿠버네티스 오브젝트 관리 를 참고한다.
kubectl
툴은 가장 일반적인 오브젝트 타입을 생성하는데 동사 형태 기반의 커맨드를
지원한다. 쿠버네티스 오브젝트 타입에 익숙하지 않은 사용자가 인지할 수 있도록 커맨드
이름이 지어졌다.
run
: 컨테이너를 실행할 새로운 파드를 생성한다.expose
: 파드에 걸쳐 트래픽을 로드 밸런스하도록 새로운 서비스 오브젝트를 생성한다.autoscale
: 디플로이먼트와 같이, 하나의 컨트롤러에 대해 자동으로 수평적 스케일이 이루어 지도록 새로운 Autoscaler 오브젝트를 생성한다.또한 kubectl
툴은 오브젝트 타입에 의해 구동되는 생성 커맨드를 지원한다.
이러한 커맨드는 더 많은 오브젝트 타입을 지원해주며 그 의도하는 바에 대해
보다 명확하게 해주지만, 사용자가 생성하고자 하는 오브젝트 타입에 대해
알 수 있도록 해야 한다.
create <오브젝트 타입> [<서브 타입>] <인스턴스명>
일부 오브젝트 타입은 create
커맨드 내 정의할 수 있는 서브 타입을 가진다.
예를 들어, 서비스 오브젝트는 ClusterIP, LoadBalancer 및 NodePort 등을
포함하는 여러 서브 타입을 가진다, 다음은 NodePort 서브 타입을 통해 서비스를
생성하는 예제이다.
kubectl create service nodeport <사용자 서비스 명칭>
이전 예제에서, create service nodeport
커맨드는
create service
커맨드의 서브 커맨드라고 칭한다.
-h
플래그를 사용하여 서브 커맨드에 의해 지원되는 인수 및 플래그를
찾아 볼 수 있다.
kubectl create service nodeport -h
kubectl
커맨드는 일반적인 몇몇의 업데이트 작업을 위해 동사 형태 기반의 커맨드를 지원한다.
이 커맨드는 쿠버네티스 오브젝트에 익숙하지 않은 사용자가 설정되어야
하는 특정 필드를 모르는 상태에서도 업데이트를 수행할 수 있도록
이름 지어졌다.
scale
: 컨트롤러의 레플리카 수를 업데이트 함으로써 파드를 추가 또는 제거하는 컨트롤러를 수평적으로 스케일한다.annotate
: 오브젝트로부터 어노테이션을 추가 또는 제거한다.label
: 오브젝트에서 레이블을 추가 또는 제거한다.kubectl
커맨드는 또한 오브젝트 측면에서 구동되는 업데이트 커맨드를 지원한다.
이 측면의 설정은 다른 오브젝트 타입에 대한 다른 필드를 설정 할 수도 있다.
set
<field>
: 오브젝트의 측면을 설정한다.kubectl
툴은 활성 오브젝트를 직접 업데이트하기 위해 추가적인 방법을 지원하지만,
쿠버네티스 오브젝트 스키마에 대한 추가적인 이해를 요구한다.
edit
: 편집기에서 구성을 열어 활성 오브젝트에 대한 원래 그대로의 구성을 바로 편집한다.patch
: 패치 문자열를 사용하여 활성 오브젝트를 바로 편집한다.
패치 문자열에 대한 보다 자세한 정보를 보려면
API 규정에서 패치 섹션을 참고한다.클러스터에서 오브젝트를 삭제하기 위해 delete
커맨드을 사용할 수 있다.
delete <타입>/<이름>
kubectl delete
를 사용할 수
있다. 차이점은 커맨드에 전해지는 인수에 있다. 명령형 커맨드로
kubectl delete
을 사용하기 위해, 삭제할 오브젝트를 인수로 전한다.
다음은 nginx라는 디플로이먼트 오브젝트를 전하는 예제이다.kubectl delete deployment/nginx
오브젝트에 대한 정보를 출력하는 몇 가지 커맨드가 있다.
get
: 일치하는 오브젝트에 대한 기본 정보를 출력한다. 옵션 리스트를 확인하기 위해 get -h
를 사용한다.describe
: 일치하는 오브젝트에 대해 수집한 상세한 정보를 출력한다.logs
: 파드에서 실행 중인 컨테이너에 대한 stdout과 stderr를 출력한다.set
커맨드 사용하기create
커맨드에 사용할 수 있는 플래그가 없는 몇 가지 오브젝트
필드가 있다. 이러한 경우, 오브젝트 생성 전에 필드에 대한 값을
정의하기 위해 set
과 create
을 조합해서 사용할 수 있다.
이는 set
커맨드에 create
커맨드의 출력을 파이프 함으로써 수행할 수 있다.
다음은 관련 예제이다.
kubectl create service clusterip my-svc --clusterip="None" -o yaml --dry-run=client | kubectl set selector --local -f - 'environment=qa' -o yaml | kubectl create -f -
kubectl create service -o yaml --dry-run=client
커맨드는 서비스에 대한 구성을 생성하지만, 이를 쿠버네티스 API 서버에 전송하는 대신 YAML 형식으로 stdout에 출력한다.kubectl set selector --local -f - -o yaml
커맨드는 stdin으로부터 구성을 읽어, YAML 형식으로 stdout에 업데이트된 구성을 기록한다.kubectl create -f -
커맨드는 stdin을 통해 제공된 구성을 사용하여 오브젝트를 생성한다.--edit
사용하기생성 전에 오브젝트에 임의의 변경을 가하기 위해 kubectl create --edit
을 사용할 수 있다.
다음은 관련 예제이다.
kubectl create service clusterip my-svc --clusterip="None" -o yaml --dry-run=client > /tmp/srv.yaml
kubectl create --edit -f /tmp/srv.yaml
kubectl create service
커맨드는 서비스에 대한 구성을 생성하고 이를 /tmp/srv.yaml
에 저장한다.kubectl create --edit
커맨드는 오브젝트를 생성하기 전에 편집을 위해 구성파일을 열어준다.쿠버네티스 오브젝트는 YAML 또는 JSON으로 작성된 오프젝트 구성파일과 함께 kubectl
커맨드 라인 툴을 이용하여 생성, 업데이트 및 삭제할 수 있다.
이 문서는 구성파일을 이용하여 어떻게 오브젝트를 정의하고 관리할 수 있는지에 대해 설명한다.
kubectl
을 설치한다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
버전 확인을 위해서, 다음 커맨드를 실행kubectl version
.kubectl
툴은 3가지 종류의 오브젝트 관리를 지원한다.
각 종류별 오브젝트 관리의 장점과 단점에 대한 논의는 쿠버네티스 오브젝트 관리를 참고한다.
구성파일로부터 오브젝트를 생성하기 위해 kubectl create -f
를 사용할 수 있다.
보다 상세한 정보는 쿠버네티스 API 참조를
참조한다.
kubectl create -f <파일명|url>
replace
커맨드로 오브젝트를 업데이트 하게되면,
구성파일에 정의되지 않은 스펙의 모든 부분이 삭제된다. 이는
externalIPs
필드가 구성파일로부터 독립적으로 관리되는
LoadBalancer
타입의 서비스와 같이, 클러스터 의해 부분적으로
관리되는 스펙의 오브젝트와 함께 사용되어서는 안된다.
독립적으로 관리되는 필드는 replace
로 삭제되는 것을 방지하기 위해
구성파일에 복사되어져야만 한다.구성파일에 따라 활성 오브젝트를 업데이트하기 위해 kubectl replace -f
를 사용할 수 있다.
kubectl replace -f <파일명|url>
구성파일에 정의한 오브젝트를 삭제하기 위해 kubectl delete -f
를
사용할 수 있다.
kubectl delete -f <파일명|url>
구성 파일이 metadata
섹션에서 name
필드 대신 generateName
필드를 지정한 경우, kubectl delete -f <filename|url>
을 사용하여
오브젝트를 삭제할 수 없다.
오브젝트를 삭제하려면 다른 플래그를 사용해야 한다. 예를 들면, 다음과 같다.
kubectl delete <type> <name>
kubectl delete <type> -l <label>
구성파일에 정의한 오브젝트에 관한 정보 확인을 위해 kubectl get -f
명령을 사용할 수 있다.
kubectl get -f <파일명|url> -o yaml
-o yaml
플래그는 전체 오브젝트 구성이 출력되도록 정의한다. 옵션의 리스트를 확인하기
위해서는 kubectl get -h
를 사용한다.
create
, replace
, 그리고 delete
명령은 각 오브젝트의 구성이
그 구성파일 내에 완전하게 정의되고 기록되어질 경우 잘 동작한다.
그러나 활성 오브젝트가 업데이트 되고, 구성파일 안에 병합되지 않으면,
업데이트 내용은 다음번 replace
가 실행될 때 삭제될 것이다.
이는 HorizontalPodAutoscaler와 같은 컨트롤러가
활성 오브젝트를 직접적으로 업데이트하도록 할 경우 발생한다.
여기 예시가 있다.
동일 오브젝트에 대해 여러 명의 작성자들로부터의 지원이 필요한 경우, 오브젝트를 관리하기 위해
kubectl apply
를 사용할 수 있다.
구성파일에 대한 URL을 가진다고 가정해보자.
kubectl create --edit
을 사용하여 오브젝트가 생성되기 전에
구성을 변경할 수 있다. 이는 독자가 수정할 수 있는 구성파일을
가르키는 튜토리얼과 작업에 특히 유용하다.
kubectl create -f <url> --edit
령형 커맨드에서 명령형 오브젝트 구성으로 전환하기 위해 몇 가지 수동 단계를 포함한다.
다음과 같이 활성 오브젝트를 로컬 오브젝트 구성파일로 내보낸다.
kubectl get <종류>/<이름> -o yaml > <종류>_<이름>.yaml
수동으로 오브젝트 구성파일에서 상태 필드를 제거한다.
이후 오브젝트 관리를 위해, replace
만 사용한다.
kubectl replace -f <종류>_<이름>.yaml
권고되는 접근방법은 다른 의미론적 의미가 없는 컨트롤러 셀렉터의 의해서만 사용되는 단일, 불변의 PodTemplate 레이블로 정의하는 것이다.
레이블 예시:
selector:
matchLabels:
controller-selector: "apps/v1/deployment/nginx"
template:
metadata:
labels:
controller-selector: "apps/v1/deployment/nginx"
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
시크릿
에는 파드가 데이터베이스에 접근하는 데 필요한 사용자 자격 증명이 포함될 수 있다.
예를 들어 데이터베이스 연결 문자열은 사용자 이름과 암호로 구성된다.
사용자 이름은 로컬 컴퓨터의 ./username.txt
파일에, 비밀번호는
./password.txt
파일에 저장할 수 있다.
echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt
이 명령에서 -n
플래그는 생성된 파일의
텍스트 끝에 추가 개행 문자가 포함되지 않도록 해 준다. 이는 kubectl
이 파일을 읽고
내용을 base64 문자열로 인코딩할 때 개행 문자도 함께 인코딩될 수 있기 때문에
중요하다.
kubectl create secret
명령은 이러한 파일들을 시크릿으로 패키징하고
API 서버에 오브젝트를 생성한다.
kubectl create secret generic db-user-pass \
--from-file=./username.txt \
--from-file=./password.txt
출력은 다음과 유사하다.
secret/db-user-pass created
기본 키 이름은 파일 이름이다. 선택적으로 --from-file=[key=]source
를 사용하여 키 이름을 설정할 수 있다.
예제:
kubectl create secret generic db-user-pass \
--from-file=username=./username.txt \
--from-file=password=./password.txt
파일에 포함하는 암호 문자열에서 특수 문자를 이스케이프하지 않아도 된다.
--from-literal=<key>=<value>
태그를 사용하여 시크릿 데이터를 제공할 수도 있다.
이 태그는 여러 키-값 쌍을 제공하기 위해 두 번 이상 지정할 수 있다.
$
, \
, *
, =
및 !
와 같은 특수 문자는
shell에 해석하고 처리하기 때문에
이스케이프할 필요가 있다.
대부분의 셸에서 암호를 이스케이프하는 가장 쉬운 방법은 암호를 작은따옴표('
)로 둘러싸는 것이다.
예를 들어, 비밀번호가 S!B\*d$zDsb=
인 경우,
다음 커맨드를 실행한다.
kubectl create secret generic db-user-pass \
--from-literal=username=devuser \
--from-literal=password='S!B\*d$zDsb='
시크릿이 생성되었는지 확인한다.
kubectl get secrets
출력은 다음과 유사하다.
NAME TYPE DATA AGE
db-user-pass Opaque 2 51s
다음 명령을 실행하여 시크릿
에 대한 상세 사항을 볼 수 있다.
kubectl describe secrets/db-user-pass
출력은 다음과 유사하다.
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 12 bytes
username: 5 bytes
kubectl get
및 kubectl describe
명령은
기본적으로 시크릿
의 내용을 표시하지 않는다. 이는 시크릿
이 실수로 노출되거나
터미널 로그에 저장되는 것을 방지하기 위한 것이다.
생성한 시크릿을 보려면 다음 명령을 실행한다.
kubectl get secret db-user-pass -o jsonpath='{.data}'
출력은 다음과 유사하다.
{"password":"MWYyZDFlMmU2N2Rm","username":"YWRtaW4="}
이제 password
데이터를 디코딩할 수 있다.
echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
출력은 다음과 유사하다.
1f2d1e2e67df
생성한 시크릿을 삭제하려면 다음 명령을 실행한다.
kubectl delete secret db-user-pass
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
먼저 새 파일에 JSON 이나 YAML 형식으로 시크릿(Secret)에 대한 상세 사항을 기록하고,
이 파일을 이용하여 해당 시크릿 오브젝트를 생성할 수 있다. 이
시크릿
리소스에는 data
와 stringData
의 두 가지 맵이 포함되어 있다.
data
필드는 base64로 인코딩된 임의의 데이터를 기입하는 데 사용된다.
stringData
필드는 편의를 위해 제공되며, 이를 사용해 시크릿 데이터를 인코딩되지 않은 문자열로
기입할 수 있다.
data
및 stringData
은 영숫자,
-
, _
그리고 .
로 구성되어야 한다.
예를 들어 시크릿에 data
필드를 사용하여 두 개의 문자열을 저장하려면 다음과 같이
문자열을 base64로 변환한다.
echo -n 'admin' | base64
출력은 다음과 유사하다.
YWRtaW4=
echo -n '1f2d1e2e67df' | base64
출력은 다음과 유사하다.
MWYyZDFlMmU2N2Rm
다음과 같이 시크릿 구성 파일을 작성한다.
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
시크릿 오브젝트의 이름은 유효한 DNS 서브도메인 이름이어야 한다.
base64
도구를 사용할 경우, 사용자는 긴 줄을 분할하는 -b
옵션을 사용해서는 안 된다.
반대로, 리눅스 사용자는 -w
옵션을 사용할 수 없는 경우
base64
명령어 또는 base64 | tr -d '\n'
파이프라인에
-w 0
옵션을 추가해야 한다.특정 시나리오의 경우 stringData
필드를 대신 사용할 수 있다. 이
필드를 사용하면 base64로 인코딩되지 않은 문자열을 시크릿에 직접 넣을 수 있으며,
시크릿이 생성되거나 업데이트될 때 문자열이 인코딩된다.
이에 대한 실제적인 예로, 시크릿을 사용하여 구성 파일을 저장하는 애플리케이션을 배포하면서, 배포 프로세스 중에 해당 구성 파일의 일부를 채우려는 경우를 들 수 있다.
예를 들어 애플리케이션에서 다음 구성 파일을 사용하는 경우:
apiUrl: "https://my.api.com/api/v1"
username: "<user>"
password: "<password>"
다음 정의를 사용하여 이를 시크릿에 저장할 수 있다.
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
stringData:
config.yaml: |
apiUrl: "https://my.api.com/api/v1"
username: <user>
password: <password>
kubectl apply
를 이용하여 시크릿 오브젝트를 생성한다.
kubectl apply -f ./secret.yaml
출력은 다음과 유사하다.
secret/mysecret created
stringData
필드는 쓰기 전용 편의 필드이다. 시크릿을 조회할 때 절대 출력되지 않는다.
예를 들어 다음 명령을 실행하는 경우:
kubectl get secret mysecret -o yaml
출력은 다음과 유사하다.
apiVersion: v1
data:
config.yaml: YXBpVXJsOiAiaHR0cHM6Ly9teS5hcGkuY29tL2FwaS92MSIKdXNlcm5hbWU6IHt7dXNlcm5hbWV9fQpwYXNzd29yZDoge3twYXNzd29yZH19
kind: Secret
metadata:
creationTimestamp: 2018-11-15T20:40:59Z
name: mysecret
namespace: default
resourceVersion: "7225"
uid: c280ad2e-e916-11e8-98f2-025000000001
type: Opaque
kubectl get
및 kubectl describe
명령은 기본적으로 시크릿
의 내용을 표시하지 않는다.
이는 시크릿
이 실수로 구경꾼에게 노출되거나
터미널 로그에 저장되는 것을 방지하기 위한 것이다.
인코딩된 데이터의 실제 내용을 확인하려면 다음을 참조한다.
시크릿 디코딩.
하나의 필드(예: username
)가 data
와 stringData
에 모두 명시되면, stringData
에 명시된 값이 사용된다.
예를 들어 다음과 같은 시크릿인 경우:
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
stringData:
username: administrator
결과는 다음과 같은 시크릿이다.
apiVersion: v1
data:
username: YWRtaW5pc3RyYXRvcg==
kind: Secret
metadata:
creationTimestamp: 2018-11-15T20:46:46Z
name: mysecret
namespace: default
resourceVersion: "7579"
uid: 91460ecb-e917-11e8-98f2-025000000001
type: Opaque
여기서 YWRtaW5pc3RyYXRvcg==
는 administrator
으로 디코딩된다.
생성한 시크릿을 삭제하려면 다음 명령을 실행한다.
kubectl delete secret mysecret
kubectl
커맨드를 사용하여 시크릿을 관리하는 방법 알아보기쿠버네티스 v1.14부터 kubectl
은
Kustomize를 이용한 쿠버네티스 오브젝트의 선언형 관리를 지원한다.
Kustomize는 시크릿 및 컨피그맵을 생성하기 위한 리소스 생성기를 제공한다.
Kustomize 생성기는 디렉토리 내의 kustomization.yaml
파일에 지정되어야 한다.
시크릿 생성 후 kubectl apply
를 통해 API
서버에 시크릿을 생성할 수 있다.
쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 한다. 이 튜토리얼은 컨트롤 플레인 호스트가 아닌 노드가 적어도 2개 포함된 클러스터에서 실행하는 것을 추천한다. 만약, 아직 클러스터를 가지고 있지 않다면, minikube를 사용해서 생성하거나 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있다.
kustomization.yaml
파일에 다른 기존 파일을 참조하는
secretGenerator
를 정의하여 시크릿을 생성할 수 있다.
예를 들어 다음 kustomization 파일은
./username.txt
및 ./password.txt
파일을 참조한다.
secretGenerator:
- name: db-user-pass
files:
- username.txt
- password.txt
kustomization.yaml
파일에 리터럴을 명시하여 secretGenerator
를
정의할 수도 있다.
예를 들어 다음 kustomization.yaml
파일에는
각각 username
과 password
에 대한 두 개의 리터럴이 포함되어 있다.
secretGenerator:
- name: db-user-pass
literals:
- username=admin