Kubernetes:驚くほど手頃な価格のパーソナルプロジェクトソリューション

こんにちは同僚!



1月、ついに待ち望まれていたKubernetesの本ができました。 ジジ・サイファンによる「Mastering Kubernetes 2nd edition」に関するスピーチ:









1年ほど前にKubernetesに関する本を出版することを敢えてしませんでした。当時の技術は間違いなくスーパー企業のd級戦艦のように見えたからです。 しかし、状況は変わりつつあり、それをサポートするために、Goについての本を書いたCaleb Doxseyの大きな記事を読むことをお勧めします。 ドキシー氏の議論は非常に興味深いものであり、それらを読んだ後、実際にKubernetesを試してみたいと願っています。



私は今年の初めにKubernetesの詳細な調査に数か月を費やしました。1つの作業プロジェクトに必要でした。 Kubernetesは、インフラストラクチャ管理のための包括的なテクノロジーであり、「バッテリーも含め、すべてが含まれています」。 Kubernetesは、大企業向けに開発するときに直面する運命にある多くの問題を解決します。 ただし、Kubernetesはマシンの大規模なクラスターの管理にのみ関連する非常に高度なテクノロジーであるという信念が再現されています。 伝えられるところでは、Kubernetesで作業するときの運用上の負荷は非常に大きいため、マシンが数十台も通らない小さなインフラストラクチャでの使用は、スズメの大砲発射です。

私はこれに反対することができます。 Kubernetesは小規模プロジェクトにも適しています。現在、1か月あたり5ドル未満で独自のKubernetesクラスタを購入できます。



Kubernetesを守る言葉



以下に、独自のKubernetesクラスターをセットアップする方法を示しますが、最初にKubernetesを小規模プロジェクトで使用する理由を説明してください。



Kubernetesは徹底的です



はい、一見、Kubernetesはやや冗長なソリューションのようです。 仮想マシンを取得して取得し、独自のアプリケーションをサービスとして構成する方が簡単なようです。なぜですか? このパスを選択するには、いくつかのソリューション、特に以下を決定する必要があります。



  1. アプリケーションをデプロイする方法は? サーバーにrsyncするだけですか?
  2. 依存関係はどうですか? PythonまたはRubyを使用している場合は、サーバーにインストールする必要があります。 コマンドを手動で実行するだけですか?
  3. アプリケーションをどのように起動しますか? バックグラウンドでバイナリを実行し、それから何もしませんか? これはおそらくあまり良いことではないので、アプリケーションをサービスとして編成する場合、systemdを学ぶ必要がありますか?
  4. すべてのアプリケーションが異なるドメイン名またはhttpパスを持っている場合、多くのアプリケーションの操作をどのように処理しますか? (おそらく、このためにhaproxyまたはnginxを構成する必要があります)
  5. アプリケーションを更新したとします。 どのようにして変更を展開しますか? サービスを停止し、コードを展開し、サービスを再起動しますか? ダウンタイムを避ける方法は?
  6. 展開をロックするとどうなりますか? ロールバックする機会はありますか? (シンボリックディレクトリ...?この単純なスクリプトは特に単純ではないようです)
  7. アプリケーションは他のサービス、たとえばredisを使用していますか? これらすべてのサービスを構成する方法は?


Kubernetesはこれらすべての問題を解決します。 当然、それらはすべて他の方法で解決できますが、Kubernetesにはより良いオプションがあります。 ただし、このことをまったく考えずに、アプリケーション開発に集中することのほうがはるかに優れています。



Kubernetesは信頼できます



単一のサーバーは常にクラッシュします。 はい、これはまれであり、おそらく年に1回ですが、そのようなイベントの後、本当の頭痛が始まります:すべてを労働条件に戻す方法。 これは、設定全体を自分で手動で設定した場合に特に当てはまります。 前回実行したすべてのチームを覚えていますか? サーバーで何が機能したか覚えていますか? bashorgからの引用を1つ思い出します。

エルノ:うーん。 コンピューターを紛失した...真剣に、_lost_。 彼は応答し、うまく動作します、私は彼がアパートのどこに行ったのかわかりません。

bash.org/?5273
最近、私自身のブログでまったく同じことが起こりました。 リンクを更新する必要がありましたが、ブログの展開方法を完全に忘れていました。 突然、10分間の修正が週末全体で作業になりました。



Kubernetesは記述形式を使用しているため、実行することになっているもの、タイミング、場所を常に把握できます。 さらに、展開されたシステムのすべてのコンポーネントがより明確に表示されます。 さらに、コントロールプレーンでは、ノード障害が慎重に処理され、炉床が自動的に再配布されます。 状態を保持しないサービス、たとえばWebアプリケーションで作業する場合、おそらく失敗を完全に忘れることができます。



Kubernetesの学習は、他の選択肢よりも難しくありません



KubernetesはUnixモデルに従っていません。 ツールのエコシステムには適合しません。 彼は「ただ一つのことをして、それをうまくやる」という決定の一人ではありません。 Kubernetesは多くの問題に対する包括的なソリューションであり、開発者がすでに慣れているさまざまなトリックやツールを置き換えることができます。



Kubernetesには独自の用語、独自のツール、独自のサーバー処理パラダイムがあり、従来のUNIXアプローチとは大きく異なります。 これらのシステムをナビゲートすると、Kubernetesの多くの特別な機能がランダムで複雑になり、おそらく残酷にさえ見えるかもしれません。 この複雑さが生じたのには十分な理由があると思いますが、ここではKubernetesが単純で理解しやすいと言っているわけではありません。 Kubernetesの知識は、インフラストラクチャの作成と維持に十分であると言っています。



これは、システム管理者が十分なUNIXのバックグラウンドを持っているということではありません。 たとえば、大学を卒業後、Windowsエコシステムで5年間働いていました。 Linuxを扱う必要があるスタートアップでの最初の仕事には、難しい変革が必要だったと言えます。 記憶のためのコマンドを知らなかった;私はほとんどすべての場面でコマンドラインを使用することに慣れていません。 新しいプラットフォームでの作業方法を学ぶのに少し時間がかかりました(その頃にはすでにプログラミングの経験がありましたが)が、どれだけ苦労したかははっきりと覚えています。



Kubernetesを使用すると、すべての作業をゼロから開始できます。 Kubernetesでは、サーバーへのSSH接続がなくてもサービスを簡単にプロビジョニングできます。 systemdを学ぶ必要はありません。 ランレベルを理解したり、どのコマンドが使用されたかを知る必要はありません: groupadd



またはaddgroup



; ps



や、神の禁じられたvimの扱い方を学ぶ必要はありません。 この材料はすべて有用で重要であり、どこにも消えることはありません。 私は、どんなUNIX環境でも自分のやり方で作業できるシステム管理者に大きな敬意を払っています。 しかし、開発者がこのような管理の微妙さを掘り下げることなく、こうしたリソースをすべて生産的に獲得できるとしたら、どれほどクールでしょうか?



本当にこれですか:



 [Unit] Description=The NGINX HTTP and reverse proxy server After=syslog.target network.target remote-fs.target nss-lookup.target [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/sbin/nginx -t ExecStart=/usr/sbin/nginx ExecReload=/usr/sbin/nginx -s reload ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target
      
      





これははるかに複雑ですか?



 apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 80
      
      





そして、これはまだ比較的良いケースです。 インフラストラクチャを100%リモートで管理する場合、手動のサーバーサポートを提供することはできません。 これを行うには、ansible、salt、chef、puppetなどの何らかのツールが必要です。 当然、Kubernetesを習得し、Kubernetesを効果的に使用するには、多くのことを学ぶ必要がありますが、これは代替案を扱うことほど難しくありません。



Kubernetesオープンソース



サーバーレス技術が非常に人気のある時代において、Kubernetesは特定のサプライヤーからの独立性が注目に値します。 Kubernetesの少なくとも3つの人気のある管理しやすいプロバイダー(Google、Amazon、Microsoft)があり、これらは近い将来に消えることはありません。 また、Kubernetesクラスターを正常に管理している企業も多くあり、そのような企業の数は日々増えています。 今日、初日からKubernetesと連携することは、ほとんどのスタートアップにとって明らかなソリューションです。

オープンソースプロジェクトであるKubernetesは、十分に文書化されており、安定しており、人気があります。また、問題はstackoverflowで可能な限り詳細に処理できます。 もちろん、Kubernetesには独自のバグと技術的な課題がありますが、私はあなたに保証します。Kubernetesを素晴らしいスキルで磨く人は世界中にいます。 彼らの仕事はあなたの配当です。 今後数年間で、この技術は改善されるだけです。



Kubernetesスケール



インフラストラクチャのサポートに関連する課題の1つはこれです。小さなシステムを展開するときに役立つテクニックは、大規模なシステムではうまく再現されないことがよくあります。 サーバーが1つしかない場合は、バイナリファイルをサーバーにSCPバインドし、プロセスを強制終了して再起動すると間違いなく便利です。 しかし、複数のサーバーを保守して同時に監視する必要がある場合、そのようなタスクは驚くほど難しいことがわかります。 そのため、このようなインフラストラクチャを管理するとき、シェフやパペットなどのツールなしではできません。



ただし、間違ったツールを選択すると、時間が経つにつれてコーナーに追い込まれる可能性があります。 突然、主要なシェフサーバーが1000サーバーの負荷に対応できず、青緑色の展開がモデルに適合せず、capistranoタスクが完了するまでに数時間かかることが判明しました。 インフラストラクチャが特定のサイズに達すると、すでに行われたすべてを破棄してやり直す必要があります。 インフラストラクチャを使用してこの永遠のリスホイールから脱出し、ニーズに応じて拡張可能なテクノロジーに切り替えることができたら、どれほど素晴らしいでしょうか?



KubernetesはSQLデータベースによく似ています。 SQLは、データストレージと効率的なクエリに関する長年の厳しい教訓の産物です。 おそらく、有効なSQLデータベースで提供されるこれらの機能の10分の1も必要になることはないでしょう。 独自のデータベースに依存して、より効率的なシステムを設計できる場合もあります。 しかし、ほとんどの場合、SQLデータベースはすべてのニーズを満たすだけでなく、既成のソリューションを迅速に発行する能力を劇的に拡大します。 SQLスキーマとインデックス作成は、ネイティブのファイルベースのデータ構造よりもはるかに使いやすいです。これは、製品が時間とともに成長および発展するにつれて、ネイティブデータ構造がほぼ確実に廃止されるためです。 ただし、SQLデータベースは、避けられないリファクタリングを生き延びます。



Kubernetesも生き残ります。 おそらく、あなたのサイドプロジェクトは、Kubernetesによってしか問題を解決できないほどの規模に成長することはありませんが、Kubernetesにはあらゆる問題に対応するツールがすべて揃っており、このツールキットを扱うときに得られるスキルは将来のプロジェクトで非常に貴重です。



独自のKubernetesクラスターを構築する



そのため、小規模なプロジェクトでKubernetesを使用することをお勧めしますが、クラスターのセットアップが簡単で安価な場合のみです。 両方とも達成可能であることがわかります。 混乱全体を自分で処理し、KubernetesホストのコントロールプレーンをサポートするKubernetes管理プロバイダーがあります。 そして、クラウドインフラストラクチャの真っdump中での最近のダンピング戦争は、そのようなサービスのコストの驚くべき削減につながりました。

Google(GKE)のKubernetesエンジンを例として使用して次のケースを分析しますが、Googleがあなたに合わない場合は、Amazon(EKS)またはMicrosoft(AKS)からのオファーも見ることができます。 独自のKubernetesクラスターを構築するには、次のものが必要です。





さらに節約するために、Google入力コントローラーなしで実行しようとします。 代わりに、各ノードでNginxをデーモンとして使用し、作業ノードの外部IPアドレスをCloudflareと同期させる独自のオペレーターを作成します。



Google設定



まず、console.cloud.google.comにアクセスして、プロジェクトを作成します(まだ行っていない場合)。 請求先アカウントも作成する必要があります。 次に、ハンバーガーメニューからKubernetesページに移動し、新しいクラスターを作成します。 次に行うことは次のとおりです。





これらすべてのオプションを設定したら、次のステップであるクラスターの作成に進むことができます。 保存する方法は次のとおりです。





そこで、3ノードのKubernetesクラスターをセットアップしました。これには、唯一のDigital Oceanマシンと同じ価格がかかりました。



GKEの構成に加えて、外部の世界からホストのHTTPポートに到達できるように、いくつかのファイアウォールルールを構成する必要もあります。 ハンバーガーメニューで[VPCネットワーク]エントリを見つけ、[ファイアウォールルール]に移動して、IPアドレス範囲が0.0.0.0/0のTCPポート80および443のルールを追加します。







ファイアウォールルール



ローカル設定



それで、クラスターを上げて開始し、それを構成しましょう。 gcloud



の指示に従ってgcloud



ツールをインストールします。 インストール後、次のようにして構成に進むことができます。



 gcloud auth login
      
      





もちろん、まだdockerをインストールし、それをGCRにバインドして、コンテナーを送信できるようにする必要があります。



 gcloud auth configure-docker
      
      





ここで説明する手順に従って、 kubectl



インストールおよび構成することもできます。



簡略化:



 gcloud components install kubectl gcloud config set project PROJECT_ID gcloud config set compute/zone COMPUTE_ZONE gcloud container clusters get-credentials CLUSTER_NAME
      
      





ちなみに、このツールキットがすべてWindows、OSX、またはLinuxで動作するのはおとぎ話にすぎません。 Windowsで時々そのようなことをした人として、私はこれが嬉しい驚きであることを認めます。



Webアプリケーションのビルド



Webアプリケーションは、任意のプログラミング言語で作成できます。 コンテナを使用すると、特定の内容を抽象化できます。 ポートでリッスンするHTTPアプリケーションを作成する必要があります。 私はそのような目的のためにGoを好むが、変化のためにクリスタルを試してみる。 main.cr



ファイルを作成します。



 # crystal-www-example/main.cr require "http/server" Signal::INT.trap do exit end server = HTTP::Server.new do |context| context.response.content_type = "text/plain" context.response.print "Hello world from crystal-www-example! The time is #{Time.now}" end server.bind_tcp("0.0.0.0", 8080) puts "Listening on http://0.0.0.0:8080" server.listen
      
      





Dockerfileも必要です。



 # crystal-www-example/Dockerfile FROM crystallang/crystal:0.26.1 as builder COPY main.cr main.cr RUN crystal build -o /bin/crystal-www-example main.cr --release ENTRYPOINT [ "/bin/crystal-www-example" ]
      
      





アプリケーションをビルドしてテストするには、次を実行します。



 docker build -t gcr.io/PROJECT_ID/crystal-www-example:latest . docker run -p 8080:8080 gcr.io/PROJECT_ID/crystal-www-example:latest
      
      





次に、localhost:8080のブラウザーに移動します。 このメカニズムを確立したら、次を実行してアプリケーションをGCRに送信できます。



 docker push gcr.io/PROJECT_ID/crystal-www-example:latest
      
      





Kubernetesを構成する



私のKubernetes設定はこちらです。



この例では、さまざまなサービスを表示するyamlファイルをいくつか作成し、kubectl applyを実行してクラスター内でそれらを構成する必要があります。 Kubernetesの設定は記述的であり、これらすべてのyamlファイルはKubernetesに取得したい状態を伝えます。 広い意味では、これが私たちがやろうとしていることです。





Webアプリケーションの構成



最初に、Webアプリケーションを設定しましょう:( PROJECT_ID



をプロジェクトのIDに置き換えてください)



 # kubernetes-config/crystal-www-example.yaml apiVersion: apps/v1 kind: Deployment metadata: name: crystal-www-example labels: app: crystal-www-example spec: replicas: 1 selector: matchLabels: app: crystal-www-example template: metadata: labels: app: crystal-www-example spec: containers: - name: crystal-www-example image: gcr.io/PROJECT_ID/crystal-www-example:latest ports: - containerPort: 8080 --- kind: Service apiVersion: v1 metadata: name: crystal-www-example spec: selector: app: crystal-www-example ports: - protocol: TCP port: 8080 targetPort: 8080
      
      





これにより、デプロイメント(拡張された構成)が作成されます。これに応じて、Kubernetesは単一のコンテナー(そこでドッカーコンテナーが動作します)とクラスター内のサービスを見つけるために使用するサービスを作成する必要があります。 この構成を適用するには、次を実行します( kubernetes-config



ディレクトリから):



 kubectl apply -f
      
      





次のようにテストできます。



 kubectl get pod #     : # crystal-www-example-698bbb44c5-l9hj9 1/1 Running 0 5m
      
      







アクセス用のプロキシAPIを作成することもできます。



 kubectl proxy
      
      





そして次に行きます: localhost :8001 / api / v1 / namespaces / default / services / crystal-www-example / proxy /



NGINXの構成



通常、HTTPサービスを使用する場合、Kubernetesは入力コントローラーを使用します。 残念ながら、GoogleのHTTPロードバランサーは高価すぎるため、使用しませんが、独自のHTTPプロキシを使用して手動で構成します(恐ろしく聞こえますが、実際には非常に簡単です)。



これを行うには、デーモンセットと構成マップを使用します。 デーモンセットは、すべてのノードで実行されるアプリケーションです。 構成マップは、原則として、コンテナにマウントできる小さなファイルです。 このファイルはnginxの設定を保存します。

yamlファイルは次のようになります。



 apiVersion: apps/v1 kind: DaemonSet metadata: name: nginx labels: app: nginx spec: selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: hostNetwork: true dnsPolicy: ClusterFirstWithHostNet containers: - image: nginx:1.15.3-alpine name: nginx ports: - name: http containerPort: 80 hostPort: 80 volumeMounts: - name: "config" mountPath: "/etc/nginx" volumes: - name: config configMap: name: nginx-conf --- apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf data: nginx.conf: | worker_processes 1; error_log /dev/stdout info; events { worker_connections 10; } http { access_log /dev/stdout; server { listen 80; location / { proxy_pass http://crystal-www-example.default.svc.cluster.local:8080; } } }
      
      





これは、構成カードのnginx.confファイルをnginxコンテナにマウントする方法です。 さらに、ホストhostNetwork: true



をバインドして外部からnginxにdnsPolicy: ClusterFirstWithHostNet



できるようにhostNetwork: true



、クラスター内のサービスにアクセスできるようにdnsPolicy: ClusterFirstWithHostNet



2つのフィールドに値を設定します。 これが行われない場合、完全に標準的な構成を取得します。



これらの式を適用すると、ノードのパブリックIPを介してnginxにアクセスできます。



これを確認する方法は次のとおりです。



 kubectl get node -o yaml # look for: # - address: ... # type: ExternalIP
      
      





これで、Webアプリケーションにインターネットからアクセスできるようになりました。 アプリケーションの美しい名前を思い付くことが残っています。



DNS接続



クラスターのノードに3 A DNSレコードを設定する必要があります。







UI Cloudflareのエントリ



次に、これらのAレコードを指すCNAMEレコードを追加します。 (例:kubernetes.example.comのwww.example.com CNAME)。 これは手動で行うことができますが、より良い-自動であるため、DNSレコードのノードをスケーリングまたは置換する必要がある場合、この情報も自動的に更新されます。



この例は、仕事の一部をKubernetesに委任し、それを克服しようとしない方法もよく示していると思います。 Kubernetesはスクリプトを理解し、強力なAPIを備えています。また、既存のスペースを独自のコンポーネントで埋めることができます。 これを行うために、次のアドレスで小さなGoアプリケーションを利用できるようにしました: kubernetes-cloudflare-sync



まず、情報提供者を作成しました。



 factory := informers.NewSharedInformerFactory(client, time.Minute) lister := factory.Core().V1().Nodes().Lister() informer := factory.Core().V1().Nodes().Informer() informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { resync() }, UpdateFunc: func(oldObj, newObj interface{}) { resync() }, DeleteFunc: func(obj interface{}) { resync() }, }) informer.Run(stop)
      
      





ノードが変更されるたびに、再同期関数を呼び出します。 次に、次のようなCloudflare APIライブラリを使用してAPIを同期します。



 var ips []string for _, node := range nodes { for _, addr := range node.Status.Addresses { if addr.Type == core_v1.NodeExternalIP { ips = append(ips, addr.Address) } } } sort.Strings(ips) for _, ip := range ips { api.CreateDNSRecord(zoneID, cloudflare.DNSRecord{ Type: "A", Name: options.DNSName, Content: ip, TTL: 120, Proxied: false, }) }
      
      





次に、Webアプリケーションと同様に、このアプリケーションをKubernetesで展開として起動します。



 apiVersion: apps/v1 kind: Deployment metadata: name: kubernetes-cloudflare-sync labels: app: kubernetes-cloudflare-sync spec: replicas: 1 selector: matchLabels: app: kubernetes-cloudflare-sync template: metadata: labels: app: kubernetes-cloudflare-sync spec: serviceAccountName: kubernetes-cloudflare-sync containers: - name: kubernetes-cloudflare-sync image: gcr.io/PROJECT_ID/kubernetes-cloudflare-sync args: - --dns-name=kubernetes.example.com env: - name: CF_API_KEY valueFrom: secretKeyRef: name: cloudflare key: api-key - name: CF_API_EMAIL valueFrom: secretKeyRef: name: cloudflare key: email
      
      





cloudflare api



キーとメールアドレスを指定して、Kubernetesシークレットを作成する必要があります。



 kubectl create secret generic cloudflare --from-literal=email='EMAIL' --from-literal=api-key='API_KEY'
      
      





また、サービスアカウントを作成する必要があります(ノードを取得するためにKubernetes APIへの展開アクセスを許可します)。 最初の実行(特にGKEの場合):



 kubectl create clusterrolebinding cluster-admin-binding --clusterrole cluster-admin --user YOUR_EMAIL_ADDRESS_HERE
      
      







そして適用します:



 apiVersion: v1 kind: ServiceAccount metadata: name: kubernetes-cloudflare-sync --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: kubernetes-cloudflare-sync rules: - apiGroups: [""] resources: ["nodes"] verbs: ["list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kubernetes-cloudflare-sync-viewer roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kubernetes-cloudflare-sync subjects: - kind: ServiceAccount name: kubernetes-cloudflare-sync namespace: default
      
      





RBACでの作業は少し面倒ですが、ここですべてが明確になることを願っています。 構成の準備が整い、アプリケーションがCloudflareで動作するようになったら、このアプリケーションを任意のノードの変更で更新できます。



おわりに



Kubernetesは、大規模システムを管理するためのフラッグシップテクノロジーになる予定です。 , Kubernetes , Kubernetes , Kubernetes , Kubernetes .



, Kubernetes : , . – !



All Articles