1. 程式人生 > >Podman 使用指南

Podman 使用指南

原文連結:Podman 使用指南

Podman 原來是 CRI-O 專案的一部分,後來被分離成一個單獨的專案叫 libpod。Podman 的使用體驗和 Docker 類似,不同的是 Podman 沒有 daemon。以前使用 Docker CLI 的時候,Docker CLI 會通過 gRPC API 去跟 Docker Engine 說「我要啟動一個容器」,然後 Docker Engine 才會通過 OCI Container runtime(預設是 runc)來啟動一個容器。這就意味著容器的程序不可能是 Docker CLI 的子程序,而是 Docker Engine 的子程序。

Podman 比較簡單粗暴,它不使用 Daemon,而是直接通過 OCI runtime(預設也是 runc

)來啟動容器,所以容器的程序是 podman 的子程序。這比較像 Linux 的 fork/exec 模型,而 Docker 採用的是 C/S(客戶端/伺服器)模型。與 C/S 模型相比,fork/exec 模型有很多優勢,比如:

  • 系統管理員可以知道某個容器程序到底是誰啟動的。

  • 如果利用 cgroup 對 podman 做一些限制,那麼所有建立的容器都會被限制。

  • SD_NOTIFY : 如果將 podman 命令放入 systemd 單元檔案中,容器程序可以通過 podman 返回通知,表明服務已準備好接收任務。

  • socket 啟用 : 可以將連線的 socket 從 systemd 傳遞到 podman,並傳遞到容器程序以便使用它們。

廢話不多說,下面我們直接進入實戰環節,本文將手把手教你如何用 podman 來部署靜態部落格,並通過 Sidecar 模式將部落格所在的容器加入到 Envoy mesh 之中。

1. 方案架構

我的部署方案涉及到兩層 Envoy:

  • 首先會有一個前端代理單獨跑一個容器。前端代理的工作是給訪問者提供一個入口,將來自外部的訪問請求轉發到具體的後端服務。

  • 其次,部落格靜態頁面由 nginx 提供,同時以 Sidecar 模式執行一個 Envoy 容器,它與 nginx 共享 network nemspace

  • 所有的 Envoy 形成一個 mesh,然後在他們之間共享路由資訊。

我之前寫過一篇用 Docker

部署 hugo 靜態部落格並配置 HTTPS 證書的文章,本文采用的是相同的方案,只是將 docker 換成了 podman,具體參考為 Envoy 開啟 TLS 驗證實戰。

2. 部署 hugo 和 sidecar proxy

我的部落格是通過 hugo 生成的靜態頁面,可以將其放到 nginx 中,其他靜態網站工具類似(比如 hexo 等),都可以這麼做。現在我要做的是讓 nginx 容器和 envoy 容器共享同一個 network namespace,同時還要讓前端代理能夠通過域名來進行服務發現。以前用 docker 很簡單,直接用 docker-compose 就搞定了,podman 就比較麻煩了,它又不能用 docker-compose,服務發現看來是搞不定了。

好不容易在 Github 上發現了一個專案叫 podman-compose,以為有救了,試用了一下發現還是不行,podman-compose 建立容器時會將欄位 network_mode: "service:hugo" 轉化為 podman CLI 的引數 --network service:hugo(真腦殘),導致容器建立失敗,報錯資訊為 CNI network "service:hugo" not found。將該欄位值改為 network_mode: "container:hugo_hugo_1" 可以啟動成功,然而又引來了另一個問題:podman-compose 的做法是為每一個 service 建立一個 pod(pod 的名字為 docker-compose.yml 所在目錄名稱),然後往這個 pod 中新增容器。我總不能將前端代理和後端服務塞進同一個 pod 中吧?只能分別為前端代理和 hugo 建立兩個目錄,然後分別建立 docker-compose.yml。這個問題解決了,下個問題又來了,podman-compose 不支援通過 service name 進行服務發現,扒了一圈發現支援 links(其實就是加個引數 --add-host),然而 links 只在同一個 pod 下才生效,我都拆分成兩個 pod 了,links 鞭長莫及啊,還是沒什麼卵用。我能怎麼辦,現在唯一的辦法就是手擼命令行了。

上面我提到了一個新名詞叫 pod,這裡花 30 秒的時間給大家簡單介紹一下,如果你是 Kubernetes 的重度使用者,對這個詞應該不陌生,但這裡確實說的是 podman 的 pod,意思還是一樣的,先建立一個 pause 容器,然後再建立業務容器,業務容器共享 pause 容器的各種 linux namespace,因此同一個 pod 中的容器之間可以通過 localhost 輕鬆地相互通訊。不僅如此,podman 還可以將 pod 匯出為 Kubernetes 的宣告式資源定義,舉個栗子:

先建立一個 pod:

$ podman pod create --name hugo

檢視 pod:

$ podman pod ls

POD ID         NAME   STATUS    CREATED         # OF CONTAINERS   INFRA ID
88226423c4d2   hugo   Running   2 minutes ago   2                 7e030ef2e7ca

在這個 pod 中啟動一個 hugo 容器:

$ podman run -d --pod hugo nginx:alpine

檢視容器:

$ podman ps

CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS            PORTS  NAMES
3c91cab1e99d  docker.io/library/nginx:alpine  nginx -g daemon o...  3 minutes ago  Up 3 minutes ago         reverent_kirch

檢視所有容器,包括 pause 容器:

$ podman ps -a

CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS            PORTS  NAMES
3c91cab1e99d  docker.io/library/nginx:alpine  nginx -g daemon o...  4 minutes ago  Up 4 minutes ago         reverent_kirch
7e030ef2e7ca  k8s.gcr.io/pause:3.1                                  6 minutes ago  Up 6 minutes ago         88226423c4d2-infra

檢視所有容器,包括 pause 容器,並顯示容器所屬的 pod id:

$ podman ps -ap

CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS            PORTS  NAMES               POD
3c91cab1e99d  docker.io/library/nginx:alpine  nginx -g daemon o...  4 minutes ago  Up 4 minutes ago         reverent_kirch      88226423c4d2
7e030ef2e7ca  k8s.gcr.io/pause:3.1                                  6 minutes ago  Up 6 minutes ago         88226423c4d2-infra  88226423c4d2

檢視 pod 中程序的資源使用情況:

$ podman pod top hugo

USER    PID   PPID   %CPU    ELAPSED           TTY   TIME   COMMAND
root    1     0      0.000   8m5.045493912s    ?     0s     nginx: master process nginx -g daemon off;
nginx   6     1      0.000   8m5.045600833s    ?     0s     nginx: worker process
nginx   7     1      0.000   8m5.045638877s    ?     0s     nginx: worker process
0       1     0      0.000   9m41.051039367s   ?     0s     /pause

將 pod 匯出為宣告式部署清單:

$ podman generate kube hugo > hugo.yaml

檢視部署清單內容:

$ cat hugo.yaml

# Generation of Kubernetes YAML is still under development!
#
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-1.0.2-dev
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: 2019-10-17T04:17:40Z
  labels:
    app: hugo
  name: hugo
spec:
  containers:
  - command:
    - nginx
    - -g
    - daemon off;
    env:
    - name: PATH
      value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    - name: TERM
      value: xterm
    - name: HOSTNAME
    - name: container
      value: podman
    - name: NGINX_VERSION
      value: 1.17.4
    - name: NJS_VERSION
      value: 0.3.5
    - name: PKG_RELEASE
      value: "1"
    image: docker.io/library/nginx:alpine
    name: reverentkirch
    resources: {}
    securityContext:
      allowPrivilegeEscalation: true
      capabilities: {}
      privileged: false
      readOnlyRootFilesystem: false
    workingDir: /
status: {}

怎麼樣,是不是有種熟悉的味道?這是一個相容 kubernetes 的 pod 定義,你可以直接通過 kubectl apply -f hugo.yaml 將其部署在 Kubernetes 叢集中,也可以直接通過 podman 部署,步驟大致是這樣的:

先刪除之前建立的 pod:

$ podman pod rm -f hugo

然後通過部署清單建立 pod:

$ podman play kube hugo.yaml

回到之前的問題,如果通過宣告式定義來建立 pod,還是無法解決服務發現的問題,除非換個支援靜態 IP 的 CNI 外掛,而支援靜態 IP 的這些 CNI 外掛又需要 etcd 作為資料庫,我就這麼點資源,可不想再加個 etcd,還是手擼命令列吧。

首先我要建立一個 hugo 容器,並指定容器的 IP:

$ podman run -d --name hugo \
  --ip=10.88.0.10 \
  -v /opt/hugo/public:/usr/share/nginx/html \
  -v /etc/localtime:/etc/localtime \
  nginx:alpine

再建立一個 envoy 容器,與 hugo 容器共享 network namespace:

$ podman run -d --name hugo-envoy \
  -v /opt/hugo/service-envoy.yaml:/etc/envoy/envoy.yaml \
  -v /etc/localtime:/etc/localtime \
  --net=container:hugo envoyproxy/envoy-alpine:latest

service-envoy.yaml 的內容如下:

static_resources:
  listeners:
  - address:
      socket_address:
        address: 0.0.0.0
        port_value: 8080
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          access_log:
          - name: envoy.file_access_log
            config:
              path: "/dev/stdout"
          route_config:
            name: local_route
            virtual_hosts:
            - name: service
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: local_service
          http_filters:
          - name: envoy.router
            config: {}
  clusters:
  - name: local_service
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    hosts:
    - socket_address:
        address: 127.0.0.1
        port_value: 80
admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8081

具體的含義請參考為 Envoy 開啟 TLS 驗證實戰。

本文開頭提到 podman 建立的容器是 podman 的子程序,這個表述可能比較模糊,實際上 podman 由兩部分組成,一個是 podman CLI,還有一個是 container runtime,container runtime 由 conmon 來負責,主要包括監控、日誌、TTY 分配以及類似 out-of-memory 情況的雜事。也就是說,conmon 是所有容器的父程序。

conmon 需要去做所有 systemd 不做或者不想做的事情。即使 CRI-O 不直接使用 systemd 來管理容器,它也將容器分配到 sytemd 相容的 cgroup 中,這樣常規的 systemd 工具比如 systemctl 就可以看見容器資源使用情況了。

$ podman ps

CONTAINER ID  IMAGE                                     COMMAND               CREATED             STATUS                 PORTS  NAMES
42762bf7d37a  docker.io/envoyproxy/envoy-alpine:latest  /docker-entrypoin...  About a minute ago  Up About a minute ago         hugo-envoy
f0204fdc9524  docker.io/library/nginx:alpine            nginx -g daemon o...  2 minutes ago       Up 2 minutes ago              hugo

對 cgroup 不熟的同學,可以參考下面這個系列:

  • 深入理解 Linux Cgroup 系列(一):基本概念

  • 深入理解 Linux Cgroup 系列(二):玩轉 CPU

  • 深入理解 Linux Cgroup 系列(三):記憶體

  • 深入理解 Kubernetes 資源限制:CPU

  • Kubernetes 記憶體資源限制實戰

  • Kubernetes Pod 驅逐詳解

零基礎的同學建議按照上面的目錄從上到下打怪升級,祝你好運!

3. 部署前端代理

這個很簡單,直接建立容器就好了:

$ podman run -d --name front-envoy \
--add-host=hugo:10.88.0.10 \
-v /opt/hugo/front-envoy.yaml:/etc/envoy/envoy.yaml \
-v /etc/localtime:/etc/localtime \
-v /root/.acme.sh/yangcs.net:/root/.acme.sh/yangcs.net \
--net host envoyproxy/envoy

由於沒辦法自動服務發現,需要通過引數 --add-host 手動新增 hosts 到容器中。envoy 的配置檔案中是通過域名來新增 cluster 的,front-envoy.yaml 內容如下:

static_resources:
  listeners:
  - address:
      socket_address:
        address: 0.0.0.0
        port_value: 80
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          access_log:
          - name: envoy.file_access_log
            config:
              path: "/dev/stdout"
          route_config:
            virtual_hosts:
            - name: backend
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/"
                redirect:
                  https_redirect: true
                  response_code: "FOUND"
          http_filters:
          - name: envoy.router
            config: {}
  - address:
      socket_address:
        address: 0.0.0.0
        port_value: 443
    filter_chains:
    - filter_chain_match:
        server_names: ["yangcs.net", "www.yangcs.net"]
      tls_context:
        common_tls_context:
          alpn_protocols: h2
          tls_params:
            tls_maximum_protocol_version: TLSv1_3
          tls_certificates:
            - certificate_chain:
                filename: "/root/.acme.sh/yangcs.net/fullchain.cer"
              private_key:
                filename: "/root/.acme.sh/yangcs.net/yangcs.net.key"
      filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
              - "yangcs.net"
              - "www.yangcs.net"
              routes:
              - match:
                  prefix: "/admin"
                route:
                  prefix_rewrite: "/"
                  cluster: envoy-ui
              - match:
                  prefix: "/"
                route:
                  cluster: hugo
                  response_headers_to_add:
                    - header:
                        key: "Strict-Transport-Security"
                        value: "max-age=63072000; includeSubDomains; preload"
          http_filters:
          - name: envoy.router
            config: {}
  clusters:
  - name: hugo
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    http2_protocol_options: {}
    hosts:
    - socket_address:
        address: hugo
        port_value: 8080
admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8001

具體的含義請參考為 Envoy 開啟 TLS 驗證實戰。

現在就可以通過公網域名訪問部落格網站了,如果後續還有其他應用,都可以參考第二節的步驟,然後重新建立前端代理,新增 --add-host引數。以我的網站 https://www.yangcs.net 為例:

我好像透露了一些什麼不得了的東西,就此打住,你也不要說,你也不要問。

4. 開機自啟

由於 podman 不再使用 daemon 管理服務,--restart 引數被廢棄了,要想實現開機自動啟動容器,只能通過 systemd 來管理了。先建立 systemd 服務配置檔案:

$ vim /etc/systemd/system/hugo_container.service

[Unit]
Description=Podman Hugo Service
After=network.target
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/podman start -a hugo
ExecStop=/usr/bin/podman stop -t 10 hugo
Restart=always

[Install]
WantedBy=multi-user.target
$ vim /etc/systemd/system/hugo-envoy_container.service

[Unit]
Description=Podman Hugo Sidecar Service
After=network.target
After=network-online.target
After=hugo_container.service

[Service]
Type=simple
ExecStart=/usr/bin/podman start -a hugo-envoy
ExecStop=/usr/bin/podman stop -t 10 hugo-envoy
Restart=always

[Install]
WantedBy=multi-user.target
$ vim /etc/systemd/system/front-envoy_container.service

[Unit]
Description=Podman Front Envoy Service
After=network.target
After=network-online.target
After=hugo_container.service hugo-envoy_container.service

[Service]
Type=simple
ExecStart=/usr/bin/podman start -a front-envoy
ExecStop=/usr/bin/podman stop -t 10 front-envoy
Restart=always

[Install]
WantedBy=multi-user.target

然後將之前停止之前建立的容器,注意:是停止,不是刪除!

$ podman stop $(podman ps -aq)

最後通過 systemd 服務啟動這些容器。

$ systemctl start hugo_container
$ systemctl start hugo-envoy_container
$ systemctl start front-envoy_container

設定開機自啟。

$ systemctl enable hugo_container
$ systemctl enable hugo-envoy_container
$ systemctl enable front-envoy_container

之後每次系統重啟後 systemd 都會自動啟動這個服務所對應的容器。

4. 總結

以上就是將部落格從 Docker 遷移到 Podman 的所有變更操作,總體看下來還是比較曲折,因為 Podman 是為 Kubernetes 而設計的,而我要求太高了,就一個資源緊張的 vps,即不想上 Kubernetes,也不想上 etcd,既想搞 sidecar,又想搞自動服務發現,我能怎麼辦,我也很絕望啊,這個事怨不得 podman,為了防止在大家心裡留下 “podman 不好用” 的印象,特此宣告一下。啥都不想要,只能自己想辦法了~~

微信公眾號

掃一掃下面的二維碼關注微信公眾號,在公眾號中回覆◉加群◉即可加入我們的雲原生交流群,和孫巨集亮、張館長、陽明等大佬一起探討雲原生技術

相關推薦

Podman 使用指南

原文連結:Podman 使用指南 Podman 原來是 CRI-O 專案的一部分,後來被分離成一個單獨的專案叫 libpod。Podman 的使用體驗和 Docker 類似,不同的是 Podman 沒有 daemon。以前使用 Docker CLI 的時候,Docker CLI 會通過 gRPC API

Java多線程編程模式實戰指南(三):Two-phase Termination模式

增加 row throws mgr 額外 finally join table 還需 停止線程是一個目標簡單而實現卻不那麽簡單的任務。首先,Java沒有提供直接的API用於停止線程。此外,停止線程時還有一些額外的細節需要考慮,如待停止的線程處於阻塞(等待鎖)或者等待狀態(等

MongoDB權威指南--筆記

這一 article dfs $natural 變慢 tags 復用 lec score mongodb並不具備一些在關系型數據庫中很普遍的功能,如連接和復雜的多行事務。 集合-->文檔-->id id在文檔所屬的集合中是唯一的。 db.help()查看數據庫級

RESTful API 設計指南

head 簡單 option eat set 取出 tro 其他 first   網絡應用程序,分為前端和後端兩個部分。當前的發展趨勢,就是前端設備層出不窮(手機、平板、桌面電腦、其他專用設備……)。   因此,必須有一種統一的機制,方便不同的前端設備與後端進行通信。這

移動H5前端性能優化指南

例如 coo forms 指南 touchend meta 大於 動畫 節點 移動H5前端性能優化指南 概述 1. PC優化手段在Mobile側同樣適用2. 在Mobile側我們提出三秒種渲染完成首屏指標3. 基於第二點,首屏加載3秒完成或使用Loading4. 基於聯通

Mysql ibd文件恢復指南

如何 文件的 表屬性 拷貝 ack eat 創建 項目 不一致 背景   mysql在使用的過程中,難免遇到數據庫表誤操作,基於此,作者親力親為,對mysql數據表ibd文件的恢復做以下詳細的說明,對開發或者初級dba提供一定的指導作用,博客中如若存在相關問題,請指明,相互

HTTP結構講解——《HTTP權威指南》系列

expire 本地 發布者 步驟 ont 資源 都是 comm pid HTTP結構 第二部分的5章主要介紹了HTTP服務器,代理,緩存,網關和機器人應用程序,這些都是Web系統架構的構造模塊。 Web服務器 第五章 Web服務器會對HTTP請求進行處理並提供響應。術語"w

Linux Unix shell 編程指南學習筆記(第四部分)

fcm 驗證 () only arguments line div 反饋 sed 第十六章 shell腳本介紹 此章節內容較為簡單,跳過。 第十七章 條件測試 test命令 expr命令 test 格式 test condition 或者 [

暴走吧!Snapdragon SDK開發速成指南

電視 新建 芯片 數據 光標 利用 android安裝 賬號 集體 (文/Aurora J) Qualcomm的Snapdragon處理器。它快如閃電、效率極高。擅長挑戰多任務極限,而且擁有攻城獅們夢寐以求的無限潛能。它能確保您的手機集4G LTE、極速體驗、長久續航

ASP.NET Zero--開發指南

.html bsp title com 開發 host log class ref ASP.NET Zero--開發指南(Lyhcee 譯) 01. 前期介紹 02. 前期要求 03. 解決方案結構(層) 04. 前端應用程序 05. 後端應用程序 06.WEB

css權威指南 讀書筆記

text ron :focus 表單 順序 系統 web letter 知識 網上看見推薦的書總是喜歡買回家,但是大多數時候都不會立即就看,都是在書櫥裏蒙上了一層灰塵。從畢業到現在,由於公司業務原因,寫js多余css,所以就想系統地看看css,並且做一些練習,於是就開始看《

XMLHttpRequest Level 2 使用指南

最後一行 互聯 t對象 cti ive ror 表單元素 單元素 style XMLHttpRequest是一個瀏覽器接口,使得Javascript可以進行HTTP(S)通信。 最早,微軟在IE 5引進了這個接口。因為它太有用,其他瀏覽器也模仿部署了,ajax操作因此得以

【轉載】 Spark性能優化指南——基礎篇

否則 內存占用 是否 進行 優先 邏輯 我們 流式 字節數組 前言 開發調優 調優概述 原則一:避免創建重復的RDD 原則二:盡可能復用同一個RDD 原則三:對多次使用的RDD進行持久化 原則四:盡量避免使用shuffle類算子 原則五:使用map-side預聚

『Python』Numpy學習指南第三章__常用函數

第一個 indices first 填充 del lib ida like otl 感覺心情漸漸變好了,加油!np.eye(2)np.savetxt(‘eye.txt‘,i2)c,v = np.loadtxt(‘data.csv‘, delimiter=‘,‘, useco

java常用集合選用指南

lan 應該 查找 排序 可重復 安全 每次 線程安全 100% java集合在選用的時候應該選那個合適?一張表告訴你該怎麽選java集合 java集合類 是否線程安全 是否鍵值對 排序 性能 元素是否可重復 擴容策略 List接

Spark SQL編程指南(Python)【轉】

res 平臺 per 它的 split 執行 文件的 分組 不同 轉自:http://www.cnblogs.com/yurunmiao/p/4685310.html 前言 Spark SQL允許我們在Spark環境中使用SQL或者Hive SQL執行關系型查詢。它的核

Spark性能優化指南——高級篇

stat 參數調優 5% 每一個 寫性能 nes fix 單獨 png Spark性能優化指南——高級篇 [TOC] 前言 繼基礎篇講解了每個Spark開發人員都必須熟知的開發調優與資源調優之後,本文作為《Spark性能優化指南》的高級篇,將深入分析數據傾斜調

網站增加《C++ Builder 操作指南》欄目,歡迎拍磚

dal cell res cpp position tsp cli welcome page 網站增加《C++ Builder 操作指南》欄目 http://www.cppfans.com/cbknowledge/opguide/ 歡迎拍磚 文檔索引 IDE外

Rsync數據同步工具應用指南

rsync 文件同步 1、Rsync數據同步工具應用指南簡介Rsync的特性:Rsync的工作方式:Rsync命令同步選項參數:本地主機模式示例遠程RPC模式示例簡介 Rsync是一款開源的、快速的、多功能的、可實現全量及增量的本地或遠程數據同步備份的優秀工具。可使本地和遠程兩臺或多臺主機之間的

const指南

進行 通過 nbsp 將不 分享 技術 tle 試圖 itl 基本詞義 意思就就是說利用const進行修飾的變量的值在程序的任意位置將不能再被修改,就如同常數一樣使用! 使用方法 const int a=1;//這裏定義了一個int類型的const常數變量a; 但