แฉแแแแก แแแแแแ แฃแแแ แแงแ แกแขแแขแแแแ, แ แแแแแแแแช แกแแฃแแแ แ แแงแ
แ แแขแแ?
Shell-แแแแ แแขแแ แแก แแแแ แกแแแแแแ แแแ แขแแแแ: แแแแแแฌแแ แแ แแแแแแแแแ Kubernetes-แแก แแแแแฅแขแแแแแแ แแ แ แแแแกแแช แแก แแแแแแแแแ แแแแฆแแแ, แแแฃแจแแแ แแแ แ แแ แแแ แแแ, แแแแฌแแแแ แแแก แแแคแแ แแแชแแ แแแแแแแแก แจแแกแแฎแแ:
แแแแก แกแแญแแ แแแแ แแแฉแแแ, แ แแแแกแแช แแแแกแขแแ แแแแก แแฃแจแแแแแก แแ แแก แแแแแฉแแแ แแชแแ แ แแแแชแแแแแ, แ แแแแแแ แแแขแแแแขแแแแชแแ แแแแแแแแแ แแแแแแแแ แกแฌแแ แ แแแแ. แงแแแแ แแก แแแขแแ แ แแแแชแแแ แแแแแแ แแ แแแ แขแแแ bash แกแแ แแแขแแแแก แแแแแงแแแแแแ, แแฃแแชแ, แ แแแแ แช แแแแแฎแกแแแแแแ, แฃแแฏแแแแกแแ แแแแ แแขแแ แแแแก แแแฌแแ แ Golang-แจแ. แชแฎแแแแ, แงแแแแแ แแกแแแ แแชแแ แ แแแแชแแแแกแแแแก แแแแ แแขแแ แแก แกแ แฃแแแแกแจแขแแแแแ แแแแแแแแ แแแแจแ แแแแแกแขแแชแแ แแ แแแคแแฅแขแฃแ แ แแฅแแแแ.
แแแแ แแขแแ แ 15 แฌแฃแแจแ
แแแแแ แจแแแฎแแแแ แแแแแแแแก, แแฃ แ แ แจแแแซแแแแ แแงแแก แแแขแแแแขแแแแ แแแฃแแ Kubernetes แแแแกแขแแ แจแ แแ แ แแแแ แจแแฃแซแแแ shell-แแแแ แแขแแ แก แแแแฎแแแ แแก. แแแแก แแแแแแแแ แแฅแแแแ แจแแแแแแ: แกแแแแฃแแแแแแแก แแแแแแ แแแ แแแแแ แแก แ แแแกแขแ แจแ แฌแแแแแแกแแแแก.
แแแแแแ, แ แแแแแแแช แแงแแแแแแ แกแฃแ แแแแแก แแแ แซแ แ แแแกแขแ แแแแ, แฃแแแ แจแแแชแแแแแก แแแแแคแแกแขแจแ แกแแแแฃแแแแก แแแฃแแก แ แแแกแขแ แจแ แฌแแแแแแก แแแแแชแแแแแแ. แแก แกแแแแฃแแแ แฃแแแ แจแแแฅแแแแก แแแแแแฃแ แกแแฎแแแแ แกแแแ แชแแจแ, แกแแแแ แจแแฅแแแแ แแแแแแก. แแก แจแแแซแแแแ แแแแแแแแก แฎแแแแ, แแแแ แแ แแฃ แแแแแงแแแแแ แแแแแแแฃแ แแแ แแแแก, แแแจแแ แแ แแ แแแแแแแชแแแก แกแแฎแแแแ แกแแแ แชแ แแแแ แ แแแฎแแแแ. แแ แแฃ แแกแแแ แแ แแ แแก 2-3 แแแแแชแฎแแแ... แกแแแแฃแแแแแแแแแก แ แแแแแแแแ แซแแแแแ แแแแ แฎแแแแ. แแ แแแแแ แแ แแ แ แแ แกแแแแฃแแแแแแแก แจแแกแแฎแแ: แแแแแ แแ แแแแแ แ แจแแแชแแแแ แแแกแแฆแแแ แ แแแกแขแ แจแ แจแแกแแกแแแแแแ. แกแแแแแแแ, แฎแแแแ แแแแ แแชแแแแ แ แแแแ แช แแแแแกแแแแแ แกแ แฃแแแแ แแ แแแคแแฅแขแฃแ แ โ แฉแแแ แแแญแแ แแแแ แแแขแแแแขแแแแ แแแ แกแแแแฃแแแแแแแก แจแแฅแแแแกแ แแ แแแแแฎแแแแแแ.
แแแ แขแแแ แแแขแแแแขแแแแชแแ
แแแแแ แแแแฌแแ แแ shell แกแแ แแแขแ, แ แแแแแแช แแแแแก แงแแแแ N แฌแแแจแ แแ แแฎแแ แแ แแแแฌแแแแก แกแแฎแแแแ แกแแแ แชแแแแก โโแกแแแแฃแแแแก แแ แกแแแแแแกแแแแก แแ แแฃ แกแแแแฃแแแ แแ แแ แแก, แแแจแแ แแก แแฅแแแแแ. แแ แแแแแฌแงแแแขแแก แฃแแแ แแขแแกแแแ แแก แแ แแก, แ แแ แแก แฐแแแแก แญแฃแ แแแก แกแแ แแแขแก cron-แจแ - แแแแกแแแฃแ แ แแ แแแกแแแแแ แแแแแแแ แงแแแแแกแแแแก. แแแแฃแกแ แแก แแ แแก, แ แแ แแแก แแแจแแแแแแก แจแแ แแก แจแฃแแแแแจแ แจแแแซแแแแ แจแแแฅแแแแก แแฎแแแ แกแแฎแแแแ แกแแแ แชแ แแ แแแ แแแแฃแแ แแ แแแก แแแแแแแแแแแจแ แแก แแแ แฉแแก แกแแแแฃแแแแแแแก แแแ แแจแ, แ แแช แแแแแแฌแแแแก แจแแชแแแแแแก แแแแแแแก แแแจแแแแแจแ.
แแแขแแแแขแแแแชแแ shell-แแแแ แแขแแ แแแ
แแแแกแแแแแก, แ แแ แฉแแแแ แกแแ แแแขแ แกแฌแแ แแ แแแฃแจแแแก, แแแแกแแแฃแ แ cron แแแจแแแแ แฃแแแ แจแแแชแแแแแก แแแจแแแแแ, แ แแแแกแแช แแแแแแขแแแ แกแแฎแแแแ แกแแแ แชแ: แแ แจแแแแฎแแแแแจแ, แจแแแแซแแแแ แจแแฅแแแแ แกแแแแฃแแแ แแแก แแแแแงแแแแแแแแ. แแแแฎแแ, แ แแแแ แแแแแแฎแแ แชแแแแแ แแก shell-แแแแ แแขแแ แแก แแแแแงแแแแแแ.
แแแ แแแ แ แแแจแ, แแแแแ แจแแแฎแแแแ แกแแ แแแขแก. Shell-แแแแ แแขแแ แแก แขแแ แแแแแแจแ แกแแ แแแขแแแก แฐแฃแแแแ แแฌแแแแแ. แงแแแแแ แแแแแแ แแ แแจแแ แแแจแแแแแกแแก --config
แแชแแแแแแก แญแฃแ แแ-แแแแ แแขแแ แก แแแกแ แจแแแแ แแก แจแแกแแฎแแ, แ.แ. แ แ แฆแแแแกแซแแแแแแแ แฃแแแ แแแแฌแงแแก แแแ. แฉแแแแก แจแแแแฎแแแแแจแ แแแแแแแงแแแแแ onKubernetesEvent
:
#!/bin/bash
if [[ $1 == "--config" ]] ; then
cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "namespace",
"event":["add"]
}
]}
EOF
fi
แแฅ แแฆแฌแแ แแแแ, แ แแ แฉแแแ แแแแแขแแ แแกแแแฃแแ แแแ แ แแแแแแแแแแก แแแแแขแแแแ (add
) แขแแแแก แแแแแฅแขแแแ namespace
.
แแฎแแ แแฅแแแ แฃแแแ แแแแแแขแแ แแแแ, แ แแแแแแช แจแแกแ แฃแแแแแ แแแแแแแแก แแแแแแแแกแแก:
#!/bin/bash
if [[ $1 == "--config" ]] ; then
# ะบะพะฝัะธะณััะฐัะธั
cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "namespace",
"event":["add"]
}
]}
EOF
else
# ัะตะฐะบัะธั:
# ัะทะฝะฐัั, ะบะฐะบะพะน namespace ะฟะพัะฒะธะปัั
createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
# ัะพะทะดะฐัั ะฒ ะฝัะผ ะฝัะถะฝัะน ัะตะบัะตั
kubectl create -n ${createdNamespace} -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
...
data:
...
EOF
fi
แแแแ! แจแแแแแ แแงแ แแแขแแ แ, แแแแแแ แกแชแแแแ แ. แแแก โแแฆแแ แซแแแแแแกโ แแ แ แแแแแฏแ แ แฉแแแ: แแแแแแแแแ แกแฃแ แแแ แแ แแแฃแจแแแ แแแแกแขแแ แจแ.
แแแแแกแแฎแฃแแแแแก แแแแแแแแแ แแแฃแญแแ
แแฃ แแแแแแแ แแแแแ แกแแ แแแขแก, แฎแแแแแ, แ แแ แแ แซแแแแแแแ แแแแแแงแแแแแ kubectl
ะธ jq
. แแก แแแจแแแแก, แ แแ แกแฃแ แแแก แฃแแแ แฐแฅแแแแแก แจแแแแแแ แแแแแแแ: แฉแแแแ hook, shell-แแแแ แแขแแ แ, แ แแแแแแช แแแแแขแแ แแแแก แแแฃแฌแแแก แแแแแแแแแก แแ แแแฃแจแแแแก Hook-แก, แแ แแ แซแแแแแแแ, แ แแแแแแแช แแแแแแงแแแแแ Hook-แแก แแแแ (kubectl แแ jq). Hub.docker.com-แก แฃแแแ แแฅแแก แแแ แกแฃแ แแแ, แ แแแแแจแแช แจแแคแฃแแฃแแแ shell-operator, kubectl แแ jq. แ แฉแแแ แแฎแแแแ แแแ แขแแแ แแแแแแก แแแแแขแแแ Dockerfile
:
$ cat Dockerfile
FROM flant/shell-operator:v1.0.0-beta.1-alpine3.9
ADD namespace-hook.sh /hooks
$ docker build -t registry.example.com/my-operator:v1 .
$ docker push registry.example.com/my-operator:v1
แกแแ แแแแ แแแแกแขแแ แจแ
แแแแแ แแแแแ แแ แแฎแแ แแแแแแฎแแแแ แแแฃแญแก แแ แแแฏแแ แแ แแแแฌแแ แแ แ แ แแแฅแแแแแแแแก แแ แ แ แแแแแฅแขแแแแ แแกแ แฃแแแแก แแก แแแแกแขแแ แจแ:
- แแฌแแ แก แกแแฎแแแแ แกแแแ แชแแก แจแแฅแแแแก แแแแแแแแแก;
- แฅแแแแก แกแแแแฃแแแแก แกแแฎแแแแ แกแแแ แชแแจแ, แแแ แแ แแแแกแ, แกแแแแช แแก แแแจแแแแฃแแแ.
แแแแแแแก, แ แแ แแแแก, แ แแแแแจแแช แฉแแแแ แกแฃแ แแแ แแฅแแแแ แแแจแแแแฃแแ, แฃแแแ แฐแฅแแแแแก แแ แแแฅแแแแแแแแแก แจแแกแ แฃแแแแแก แแแแแ แแแ. แแก แจแแแซแแแแ แแแแแแแแก แแฅแแแแ แกแแแฃแแแ แ แกแแ แแแกแแก แแแแแ แแจแแก แจแแฅแแแแ. แแแแแ แแแ แฃแแแ แแแแแแแแก ClusterRole แแ ClusterRoleBinding แกแแฎแแ, แ แแแแแ แฉแแแ แแแแแแขแแ แแกแแแก แแแแแฅแขแแแ แแแแแ แแแกแแขแฃแ แแแแ.
YAML-แจแ แกแแแแแแ แแฆแฌแแ แ แแกแ แแแแแแงแฃแ แแแ:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: monitor-namespaces-acc
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: monitor-namespaces
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "create", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: monitor-namespaces
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: monitor-namespaces
subjects:
- kind: ServiceAccount
name: monitor-namespaces-acc
namespace: example-monitor-namespaces
แแฅแแแ แจแแแแซแแแแ แแแฃแจแแแ แแฌแงแแแแแ แกแฃแ แแแ, แ แแแแ แช แแแ แขแแแ แแแแแแแแแ:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-operator
spec:
template:
spec:
containers:
- name: my-operator
image: registry.example.com/my-operator:v1
serviceAccountName: monitor-namespaces-acc
แแแฎแแ แฎแแแฃแแแแแกแแแแก แแฅแแแแแ แชแแแแ แกแแฎแแแแ แกแแแ แชแ, แกแแแแช แแแแฅแแแแแแแ shell-แแแแ แแขแแ แ แแ แแแแแงแแแแแฃแแ แแฅแแแแ แจแแฅแแแแแ แแแแแคแแกแขแแแ:
$ kubectl create ns example-monitor-namespaces
$ kubectl -n example-monitor-namespaces apply -f rbac.yaml
$ kubectl -n example-monitor-namespaces apply -f deployment.yaml
แกแฃแ แแก แแ แแก: shell-แแแแ แแขแแ แ แแแแฌแงแแแก, แแแแแแฌแแ แก แกแแฎแแแแ แกแแแ แชแแก แจแแฅแแแแก แฆแแแแกแซแแแแแแก แแ แกแแญแแ แแแแแก แจแแแแฎแแแแแจแ แแฌแแ แแแแแก Hook-แก.
แแแแแแแ, แแแ แขแแแ shell แกแแ แแแขแ แแแแแแฅแชแ Kubernetes-แแก แแแแแแแ แแแแ แแขแแ แแ แแ แแฃแจแแแแก แ แแแแ แช แแแแกแขแแ แแก แแแฌแแแ. แแ แแก แงแแแแแคแแ แ Golang-แจแ แแแแ แแขแแ แแแแก แแแแแแแแ แแแแก แ แแฃแแ แแ แแชแแกแแก แแแ แแจแ:
แแ แกแแแแแฎแแ แแแแแ แแ แแ แแแฃแกแขแ แแชแแแ...
แแแก แแแแจแแแแแแแแก แฃแคแ แ แแแขแแแฃแ แแ แแแแแชแแแแแ แแ แ-แแ แ แจแแแแแ แแฃแแแแแแชแแแจแ.
แคแแแขแ แแชแแ
แแแแแฅแขแแแแก แแแแแงแฃแ แแก แแแแแแแ แแแ แแแ, แแแแ แแ แฎแจแแ แแ แกแแญแแ แแ แ แแแแแ แแแ แแแแแแ แแ แแแแแฅแขแแก แแแแกแแแแแแก แจแแชแแแแแแแแแแแแ, Deployment-แจแ แแกแแแแแก แ แแแแแแแแแก แจแแกแแชแแแแแแ แแ แแแแแฅแขแแแแก แแขแแแแขแแแแก แจแแกแแชแแแแแแ.
แ แแแแกแแช แแแแแแแ แแแแแก, shell-แแแแ แแขแแ แ แแฆแแแก แแแแแฅแขแแก JSON แแแแแคแแกแขแก. แฉแแแ แจแแแแแซแแแ แจแแแแ แฉแแแ แแก แแแแกแแแแแ, แ แแแแแแแช แแแแแแขแแ แแกแแแก แแ JSON-แจแ แแ แแแแฃแจแแแ Hook แแฎแแแแ แ แแแแกแแช แแกแแแ แแชแแแแแแแ. แแแแกแแแแก แแ แแก แแแแ jqFilter
, แกแแแแช แแฅแแแ แฃแแแ แแแฃแแแแแ jq แแแแแฎแแขแฃแแแแ, แ แแแแแแช แแแแแงแแแแแฃแแ แแฅแแแแ JSON manifest-แแ.
แแแแแแแแแ, แแแแแแแแแแก แแแแแฅแขแแแแก แแขแแแแขแแแแก แชแแแแแแแแแแ แ แแแแแ แแแแกแแแแก, แแฅแแแ แฃแแแ แแแคแแแขแ แแ แแแแ labels
แแแแแแ แก แแแ แแ metadata
. แแแแคแแแฃแ แแชแแ แแฅแแแแ แแกแแแ:
cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "deployment",
"event":["update"],
"jqFilter": ".metadata.labels"
}
]}
EOF
แแก jqFilter แแแแแฎแแขแฃแแแแ แแฅแชแแแก Deployment-แแก แแ แซแแ JSON แแแแแคแแกแขแก แแแแแ JSON-แแ แแแแแแแแแ:
shell-แแแแ แแขแแ แ แแแฃแจแแแแก Hook-แก แแฎแแแแ แแแจแแ, แ แแแแกแแช แแก แแแแแ JSON แจแแแชแแแแแ แแ แกแฎแแ แแแแกแแแแแแก แชแแแแแแแแแ แแแแแ แแ แแแฃแแ แแฅแแแแ.
Hook แแแจแแแแแก แแแแขแแฅแกแขแ
Hook-แแก แแแแคแแแฃแ แแชแแ แกแแจแฃแแแแแแก แแแซแแแแ แแแฃแแแแแ แแแแแแแแแแก แ แแแแแแแแ แแแ แแแแขแ - แแแแแแแแแ, 2 แแแ แแแแขแ แฆแแแแกแซแแแแแแแกแแแแก Kubernetes-แแแ แแ 2 แแแแ แแแ:
{"onKubernetesEvent":[
{"name":"OnCreatePod",
"kind": "pod",
"event":["add"]
},
{"name":"OnModifiedNamespace",
"kind": "namespace",
"event":["update"],
"jqFilter": ".metadata.labels"
}
],
"schedule": [
{ "name":"every 10 min",
"crontab":"* */10 * * * *"
}, {"name":"on Mondays at 12:10",
"crontab": "* 10 12 * * 1"
]}
แแชแแ แ แแแแแฎแแแแ: แแแแฎ, Shell-แแแแ แแขแแ แแก แแฎแแ แแแญแแ แ crontab แกแขแแแแก แกแแ แแแขแแแแก แแแจแแแแ. แแแแแขแแแแแ แแแขแแแแแ แจแแแแซแแแแ แแฎแแแแ
แแแแก แแแกแแ แแแแแแ, แแฃ แ แแขแแ แแแฃแจแแ แแแแแแ, shell-แแแแ แแขแแ แ แฅแแแแก แแ แแแแแ แคแแแแก แแ แแแแแกแชแแแก แแแกแแแ แแแแแแแ แแแแก แชแแแแแจแ Hook-แจแ. BINDING_CONTEXT_TYPE
. แคแแแแ แจแแแชแแแก Hook-แแก แแแจแแแแแก แแแแแแก JSON-แแก แแฆแฌแแ แแก. แแแแแแแแแ, แงแแแแ 10 แฌแฃแแจแ แแแฃแญแ แแแฃแจแแแแแก แจแแแแแแ แจแแแแแ แกแแ:
[{ "binding": "every 10 min"}]
แแ แแ แจแแแแแก แแแแฌแงแแแ แแแแ:
[{ "binding": "every 10 min"}, { "binding": "on Mondays at 12:10"}]
แแงแแแแแ onKubernetesEvent
แแฅแแแแ แแแขแ JSON แขแ แแแแ แแแ, แ แแแแแ แแแ แจแแแชแแแก แแแแแฅแขแแก แแฆแฌแแ แแก:
[
{
"binding": "onCreatePod",
"resourceEvent": "add",
"resourceKind": "pod",
"resourceName": "foo",
"resourceNamespace": "bar"
}
]
แแแแแแแก แจแแแแแแกแแก แแแแแแ แจแแกแแซแแแแแแแ แแแแ แกแแฎแแแแแแแแ แแ แแแขแ แแแขแแแแแแก แฌแแแแแฎแแ แจแแแแซแแแแ resourceName
jq-แแก แแแแแงแแแแแ แฃแแแ แแแฉแแแแแแแ แแแฃแญแจแ, แ แแแแแแช แแแแแ แแแก แกแแแแฃแแแแแแแแก:
jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH
แแฅแแแ แจแแแแซแแแแ แแแแฆแแ แกแฎแแ แแแแแแ แแแแแแแแฃแ แแ.
แ แ แแ แแก แจแแแแแแ?
แแ แแแฅแขแแก แกแแชแแแจแ, แฅ
แแ แกแแแแแก แแ แแแแแแก แแแแแงแแแแแแ แแแขแ แแแแก แจแแแ แแแแแแก แแฎแแ แแแญแแ แ - แฎแแแแแกแแฌแแแแแ แแแขแ แแแ แแฆแฌแแ แแแแ แแแแงแแคแแแแแแจแ
แ แแแแ แช แแฅแแแ แแแแแ แแแฎแแแแแแ, shell-แแแแ แแขแแ แ แแแฌแแ แแแแ Go-แจแ แแ แแแฌแแแแแแ แฆแแ แฌแงแแ แแก แแแชแแแแแแ (Apache 2.0). แฉแแแ แแแแแแแแแ แแแฅแแแแแ แแแแแแแแ แแแแก แแแแแกแแแแ แ แแแฎแแแ แแแแกแแแแก
แกแแแแฃแแแแแแแก แคแแ แแแก แแแฎแกแแแ, แแกแแแ แแแชแแแแแแ, แ แแ แญแฃแ แแ-แแแแ แแขแแ แแ ะฝะตะฑะพะปััะฐั แฉแแแแ แกแแกแขแแแแก แแแฌแแแ, แ แแแแแกแแช แจแแฃแซแแแ แแแแแแฎแแแก Kubernetes แแแแกแขแแ แจแ แแแแแกแขแแแแ แแแฃแแ แแแแแแแขแแแ แแ แจแแแกแ แฃแแแก แกแฎแแแแแกแฎแแ แแแขแแแแขแฃแ แ แแแฅแแแแแแแแ. แฌแแแแแแฎแแ แแแขแ แแ แกแแกแขแแแแก แจแแกแแฎแแ
แฉแแแ แแแแฅแแก แแแแแ, แ แแ แแแแฎแกแแแ แแ แกแแกแขแแแแก แแแแแ แฉแแแ แแแฌแแแ: แแแแแแแขแแก แแแแ แแขแแ แ แแ แฉแแแแ แแแฃแญแแแแกแ แแ แแแแฃแแแแแก แแแแแฅแชแแ. แกแฎแแแแ แจแแ แแก, addon-แแแแ แแขแแ แ แฃแแแ แแ แแก
แแแแแแแ แแแแแงแฃแ แ!
PS
แแกแแแ แฌแแแแแแฎแแ แฉแแแแก แแแแแแ:
- ยซ
แแแแ แแขแแ แแแ Kubernetes-แแกแแแแก: แ แแแแ แแแแฃแจแแแ แกแแฎแแแแฌแแคแ แแแแแแแชแแแแ "; - ยซ
Kubernetes-แแกแแแแก แแแแ แแขแแ แแก แแแฌแแ แ แแแแแแแจแ "; - ยซ
แฌแแ แแแแแแแแแ แแฎแแ แแแแแแแขแก Grafana-แกแแแแก - Statusmap แแแแแแ "; - ยซ
แฌแแ แแแแแแแแแ loghouse - แฆแแ แแแแแก แกแแกแขแแแแก Kubernetes-แจแ แแฃแ แแแแแแแแ แแฃแจแแแแแกแแแแก "; - ยซ
แฉแแแ แแคแแชแแแแฃแ แแ แฌแแ แแแแแแแแแ dapp - DevOps แแ แแแ แแแแก CI/CD แจแแแแ แฉแฃแแแแแกแแแแก ".
แฌแงแแ แ: www.habr.com