Knative
1. Installation
- Cert-Manager: version 1.3 이하만 됩니다. 체크 필요! (나중에 에러남)
- Istio 따로 설치 하지 말고, 여기 있는 문서에서 Knative 먼저 설치후 추가로 Networking Layer 설정시에 Istio 설정함
1.1 Check Version
# Knavtive Server 버젼 확인
$ kubectl get namespace knative-serving -o 'go-template={{index .metadata.labels "serving.knative.dev/release"}}'
v0.11.2
# Knative Eventing 버젼 확인
$ kubectl get namespace knative-eventing -o 'go-template={{index .metadata.labels "eventing.knative.dev/release"}}'
1.2 Install Knative CLI
kn 명령을 내릴수 있는 클라이언트를 먼저 설치 합니다.
$ wget https://storage.googleapis.com/knative-nightly/client/latest/kn-linux-amd64
$ chmod 110 kn-linux-amd64
$ sudo mv kn-linux-amd64 /usr/local/bin/kn
1.3 Delete Existing Serving Component
강제로 업그레이드시 apply를 delete로 변경하고 이후 apply진행합니다. (서비스 안하고 있다는 전제)
일단 삭제이유는 kubeflow로 설치이후 버젼 업그레이드가 목적입니다.
귀찮아서 업그레이드 방식 따르지 않고 그냥 다 삭제해버리고 다시 깔아버리는 방법입니다.
바로 아래 코드는 서비스를 안하고 있을경우 강제로 업그레이드 하기 위해서 먼저 삭제부터 하는 코드 입니다.
주의하세요!!
$ kubectl get namespaces knative-serving -o json | jq '.spec.finalizers'=null | kubectl apply -f -
$ kubectl delete -f https://storage.googleapis.com/knative-nightly/serving/latest/serving-core.yaml
$ kubectl delete -f https://storage.googleapis.com/knative-nightly/serving/latest/serving-crds.yaml
$ kubectl delete -f https://github.com/knative/operator/releases/download/knative-v1.1.0/operator.yaml
$ kubectl get namespaces knative-serving
NAME STATUS AGE
knative-serving Terminating 44m
위를 확인해보면 Terminating에서 멈춰서 더이상 진행이 되지 않습니다.
Finelizer 부분을 설정해줘야 합니다.
참고로 그냥 edit으로 안됩니다.
$ kubectl get namespaces knative-serving -o json > knative-serving.json
$ vi knative-serving.json
안에 보면 finalizers 라고 있을겁니다.
"spec": {
"finalizers": [
"kubernetes"
]
}
finalizers 부분을 삭제하고 저장합니다.
"spec": {
"finalizers": [
]
}
주소를 알아내고, 편집한 json 파일로 대체를 합니다.
이때 알아낸 selfLink의 주소 뒤에 /finalize
를 붙여줘야 합니다.
$ kubectl get namespace knative-serving -o json | jq .metadata.selfLink
"/api/v1/namespaces/knative-serving"
$ kubectl replace --raw "/api/v1/namespaces/knative-serving/finalize" -f ./knative-serving.json
이후 kubectl get namespaces
로 확인해보면 삭제되어 있을겁니다.
1.4 Install Serving Component
Serving을 설치합니다.
$ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.1.0/serving-crds.yaml
$ kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.1.0/serving-core.yaml
Knative Component를 설치합니다.
자세한 설치방법은 링크 를 참조 합니다.
- Knative Operator 는 default namespace에 설치가 되야 합니다.
$ kubectl config set-context --current --namespace=default
$ kubectl apply -f https://github.com/knative/operator/releases/download/knative-v1.1.0/operator.yaml
$ kubectl get deployment knative-operator
NAME READY UP-TO-DATE AVAILABLE AGE
knative-operator 1/1 1 1 20s
1.5 Install Istio
반드시 아래에 있는 방법으로 설치를 해야지 Knative가 정상 작동합니다.
따로 Istio에 있는 문서대로 하면 설치가 안됩니다.
$ kubectl apply -l knative.dev/crd-install=true -f https://github.com/knative/net-istio/releases/download/knative-v1.1.0/istio.yaml
$ kubectl apply -f https://github.com/knative/net-istio/releases/download/knative-v1.1.0/istio.yaml
$ kubectl apply -f https://github.com/knative/net-istio/releases/download/knative-v1.1.0/net-istio.yaml
# 확인
$ kubectl --namespace istio-system get service istio-ingressgateway
1.5 cluster-local-gateway 설정
자세한 설치방법은 링크 를 참조 합니다.
cat << EOF > ./istio-minimal-operator.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
values:
global:
proxy:
autoInject: disabled
useMCP: false
# The third-party-jwt is not enabled on all k8s.
# See: https://istio.io/docs/ops/best-practices/security/#configure-third-party-service-account-tokens
jwtPolicy: first-party-jwt
addonComponents:
pilot:
enabled: true
prometheus:
enabled: false
components:
ingressGateways:
- name: istio-ingressgateway
enabled: true
- name: cluster-local-gateway
enabled: true
label:
istio: cluster-local-gateway
app: cluster-local-gateway
k8s:
service:
type: ClusterIP
ports:
- port: 15020
name: status-port
- port: 80
targetPort: 8080
name: http2
- port: 443
targetPort: 8443
name: https
EOF
실행
$ istioctl install -f istio-minimal-operator.yaml
This will install the Istio 1.11.0 default profile with ["Istio core" "Istiod" "Ingress gateways"] components into the cluster. Proceed? (y/N) y
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Installation complete
Thank you for installing Istio 1.11.
# 설치 확인
$ kubectl get pods --namespace istio-system
NAME READY STATUS RESTARTS AGE
cluster-local-gateway-c9d6b9dbf-2tqh5 1/1 Running 0 5m55s
istio-ingressgateway-754f55757d-sqgrk 1/1 Running 0 5m55s
istiod-59b95457f9-x5fcc 1/1 Running 0 8m19s
$ kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cluster-local-gateway ClusterIP 172.20.87.103 <none> 15020/TCP,80/TCP,443/TCP 6m31s
istio-ingressgateway LoadBalancer 172.20.107.71 a1234567890abcdefghijklmnopqrstu-123456789.ap-northeast-2.elb.amazonaws.com 15021:31476/TCP,80:30369/TCP,443:31261/TCP 62m
istiod ClusterIP 172.20.138.114 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 62m
knative-local-gateway ClusterIP 172.20.106.201 <none> 80/TCP 15m
1.6 Install Eventing Component
- KServing 설치시 필요없는 component
Custom Resource Definitions (CRD) 그리고 핵심 core components를 설치 합니다.
$ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.1.0/eventing-crds.yaml
$ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.1.0/eventing-core.yaml
모두 정상 작동 하는지 확인
$ kubectl get pods -n knative-eventing
NAME READY STATUS RESTARTS AGE
eventing-controller-56ccd89cd8-xxn9c 1/1 Running 0 39s
eventing-webhook-76b66cd56c-vrpzc 1/1 Running 0 38s
Broker Layer는 Apache Kafka, MT-Channel-based, RabbitMQ 등을 지원하고 있습니다.
MT Broker는 다음과 같이 설치 합니다.
자세한 내용은 링크를 확인합니다.
$ kubectl apply -f https://github.com/knative/eventing/releases/download/knative-v1.1.0/mt-channel-broker.yaml
2. Configuration
2.1 Custom Domain Setup
Knative Serving Route는 기본값으로 example.com 을 기본 도메인으로 사용합니다.
이후 KFServing을 할때도 모두 example.com 으로 나오기 때문에 이 부분의 변경이 반드시 필요 합니다.
$ kubectl edit cm config-domain --namespace knative-serving
처음 열면 아래와 같은 형식으로 생겼는데..
example:_| 로 시작하는 부분을 모두 삭제 합니다.
example.com 까지 모두 삭제 했으면, example.com 도메인을 변경합니다.
apiVersion: v1
data:
_example: |
################################
# #
# EXAMPLE CONFIGURATION #
# #
################################
# ...
example.com: |
kind: ConfigMap
변경이후 다음과 같습니다.
apiVersion: v1
data:
example.org: |
selector:
app: nonprofit
ml.incredible.ai: ""
svc.cluster.local: |
selector:
app: cluster-local
3. Getting Started
3.1 Hello World in Python
Python App
cat <<EOF > app.py
import os
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
target = os.environ.get('TARGET', 'World')
return 'Hello {}!\n'.format(target)
if __name__ == "__main__":
app.run(debug=True,host='0.0.0.0',port=8080)
EOF
Dockerfile & Build
cat <<EOF > Dockerfile
FROM python:3.7-slim
ENV PYTHONUNBUFFERED=True
ENV APP_HOME=/app
WORKDIR \$APP=HOME
COPY . ./
RUN pip install Flask gunicorn
CMD exec gunicorn --bind :\$PORT --workers 1 --threads 8 --timeout 0 app:app
EOF
$ docker login
$ docker build -t andersonjo/knative-hello-world .
$ docker push andersonjo/knative-hello-world
Service & Deploy
andersonjo 부분을 Docker Hub 아이디로 변경 필요
cat <<EOF > service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld-python
namespace: knative-samples
spec:
template:
spec:
containers:
- name: helloworld-python
image: docker.io/andersonjo/knative-hello-world
imagePullPolicy: IfNotPresent
env:
- name: TARGET
value: "Python Sample v1"
EOF
$ kubectl apply -f service.yaml
$ kubectl get ksvc helloworld-python -n knative-samples
NAME URL LATESTCREATED LATESTREADY READY REASON
helloworld-python http://helloworld-python.default.ai.platform helloworld-python-69cbt helloworld-python-69cbt True
$ INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
$ curl -H "Host:helloworld-python.default.ai.platform" $INGRESS_HOST
$ curl -H "Host:helloworld-python.default.ml.inthewear.com" $INGRESS_HOST
Hello Python Sample v1!
3. Autoscale
3.1 Autoscaler Types
- Knative Pod Autoscaler (KPA)
- Knative Serving Core의 한 부분이며, 디폴트값이 사용이다.
- 트래픽이 없을경우 0으로 scale 하는 기능도 있음 (scale down)
- CPU 기반의 autoscaling은 지원하지 않음
- Horizontal Pod Autoscaler (HPA)
- Knative Serving Core에서 제공되는 기능이 아니며, Knative Serving 설치이후 따로 설정해줘야 함
- 트래픽이 없을 경우 0으로 scale down하는 기능이 없음
- CPU 기반의 autoscaling 제공
설정은 class
annotation을 설정해서 타입을 설정 할 수 있습니다.
- Global Settings Key:
pod-autoscaler-class
- Per-revision annotation key:
autoscaling.knative.dev/class
- Possible values:
kpa.autoscaling.knative.dev
orhpa.autoscaling.knative.dev
- Default:
kpa.autoscaling.knative.dev
3.2 Configuration
3.2.1 Per Revision Example
spec.template.metadata.annotations 여기에서 autoscaling.knative.dev/class
설정
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld-go
namespace: default
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/class: "kpa.autoscaling.knative.dev"
spec:
containers:
- image: gcr.io/knative-samples/helloworld-go
3.2.2 Global(ConfigMap)
$ kubectl edit configmap config-autoscaler -n knative-serving
apiVersion: v1
kind: ConfigMap
metadata:
name: config-autoscaler
namespace: knative-serving
data:
pod-autoscaler-class: "kpa.autoscaling.knative.dev"
3.2.3 Global(Operator)
$ kubectl edit configmap config-autoscaler -n knative-serving
apiVersion: operator.knative.dev/v1alpha1
kind: KnativeServing
metadata:
name: knative-serving
spec:
config:
autoscaler:
pod-autoscaler-class: "kpa.autoscaling.knative.dev"
3.3 Example
cat <<EOF > service.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: autoscale-go
namespace: default
spec:
template:
metadata:
annotations:
# Target 10 in-flight-requests per pod.
autoscaling.knative.dev/target: "10"
spec:
containers:
- image: gcr.io/knative-samples/autoscale-go:0.1
EOF
$ kubectl apply -f service.yaml
$ kubectl get ksvc autoscale-go
NAME URL LATESTCREATED LATESTREADY READY REASON
autoscale-go http://autoscale-go.default.ai.platform autoscale-go-xdstf autoscale-go-xdstf True
$ INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
$ curl -H "Host:autoscale-go.default.ai.platform" "${INGRESS_HOST}?sleep=500&prime=10000&bloat=5"
Allocated 5 Mb of memory.
The largest prime less than 10000 is 9973.
Slept for 500.11 milliseconds.
Load Test를 진행합니다.
$ hey -z 30s -c 200 -H "Host: autoscale-go.default.ai.platform" "http://${INGRESS_HOST}?sleep=5000&prime=1000000&bloat=20"
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
autoscale-go-2fkh2-deployment-65bc9d7764-zq2sr 2/2 Running 0 5m17s
autoscale-go-5n6gm-deployment-657678f8bd-xp87n 2/2 Running 0 6m31s
autoscale-go-dm54z-deployment-c48fcb7ff-49ckr 2/2 Running 0 179m