最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

從docker容器時間問題探究到Namespace問題詳解

 更新時間:2025年10月02日 16:36:21   作者:CN-FuWei  
文章講述在K8s測試環(huán)境中修改容器時間失敗的問題,發(fā)現(xiàn)需添加--cap-add SYS_TIME參數(shù)但導(dǎo)致宿主機時間同步,進而深入探討Docker的Namespace隔離機制和libfaketime工具的使用,最終通過自定義鏡像實現(xiàn)容器時間獨立修改

一、容器的時間問題

在測試環(huán)境已經(jīng)全面使用 k8s 部署了,今天突然有一個測試同學(xué),因為特殊場景,希望更改一下服務(wù)對應(yīng)的容器時間,當(dāng)時我心想,這不是挺簡單的。

于是就來到容器當(dāng)中,執(zhí)行如下命令進行更改:

[root@a-admin-f478dbd55-ddv7x /]# date
Tue Jun 18 14:01:34 CST 2019
[root@a-admin-f478dbd55-ddv7x /]# date -s 05/28
date: cannot set date: Operation not permitted
Tue May 28 00:00:00 CST 2019
[root@a-admin-f478dbd55-ddv7x /]# date
Tue Jun 18 14:01:48 CST 2019

報了一個錯誤

date: cannot set date: Operation not permitted

而且也沒有更改成功。當(dāng)時還不知道一些深層次的原因,于是開始了搜索之旅。

最先搜索到的,是解決 date 命令報錯的問題:需要在啟動容器的時候,加上--cap-add SYS_TIME的參數(shù)。

docker run -it --cap-add SYS_TIME --name centos centos /bin/bash

簡單說明一下這里添加的參數(shù),深入的后邊探討。

在添加這些特殊權(quán)限的時候,可以有如下幾種操作:

  • --cap-add:給容器添加某個權(quán)限。
  • --cap-drop:去掉容器的某個權(quán)限。
  • --privileged:將所有的權(quán)限添加給容器。
  • --cap-drop ALL:去掉所有權(quán)限。

然后再進入到容器里,重復(fù)執(zhí)行上邊改時間的操作,就能成功了。

因為目前使用 rancher 進行 k8s 的管理,因此掛載的方式如下,可點擊pod升級,在高級選項的最后,有增加內(nèi)核的選項,選中SYS_TIME,然后點擊升級即可。

事實上可能問題到這里,就已經(jīng)沒有問題了,但是接著測試同學(xué)發(fā)現(xiàn),時間會自動又變成現(xiàn)在的時間了,以至于無法進行測試,我當(dāng)時心想,難道說,k8s 自己有這樣的時間修正機制么,,,

后來想到會不會是定時任務(wù)的因素,于是乎,來到了剛剛那個容器所在的主機之上,一看,果然有時間校準(zhǔn)的定時任務(wù),每分鐘執(zhí)行一次,于是注釋掉,再次更改容器時間,這次才真正的生效,與此同時,發(fā)現(xiàn)了另外一個重大問題,那就是容器時間變更為 5 月 28 日之后,宿主機的時間也跟著變更了,讓我一陣兒惶恐,盡管這是在測試環(huán)境,宿主機的時間更改可也不是鬧著玩的呀

到后來才知道,原來上邊操作的 --cap-add SYS_TIME是為了將宿主機的內(nèi)核時間掛載進來與容器共享,因此容器時間更改了,宿主機時間也會跟著更改。說到底,還是對 docker 理解不深的緣故,但是借著這個機緣,倒是靜下心來,看了如下的一些資料,讓自己對容器技術(shù)有了新的一層認識。

二、docker 之 Namespace

內(nèi)核為容器提供了兩種技術(shù)cgroupnamespace,分別對容器進行資源限制資源隔離。

  • 容器本質(zhì)是進程,cgroup用來限制容器的資源使用量,避免單個容器耗盡系統(tǒng)資源。
  • namespace用來隔離容器與宿主機,以及不同的容器。

這里,就先針對 namespace 這個概念進行一下探析。

Namespace系統(tǒng)調(diào)用參數(shù)隔離內(nèi)容內(nèi)核版本
UTSCLONE_NEWUTS主機名與域名2.6.19
IPCCLONE_NEWIPC信號量,消息隊列和共享內(nèi)存2.6.19
PIDCLONE_NEWPID進程編號2.6.24
NetworkCLONE_NEWNET網(wǎng)絡(luò)設(shè)備,網(wǎng)絡(luò)棧,端口等2.6.29
MountCLONE_NEWNS掛載點(文件系統(tǒng))2.4.19
UserCLONE_NEWUSER用戶和用戶組3.8

如上列出的這六項,是目前構(gòu)建一個容器所默認賦予的基礎(chǔ)能力,可以有別于原宿主機而在容器當(dāng)中單獨存在(當(dāng)然還是基于宿主機),這個時候就能夠理解,上邊改時間的操作之所以失敗,就是因為默認情況下,容器是沒有 Time(時間)這個 Namespace 的,通過--cap-add SYS_TIME掛載也是引用了系統(tǒng)的內(nèi)核時間,因此改了容器時間之后,系統(tǒng)時間跟著變化,也就不稀奇了。

1、UTS namespace

UTS(UNIX Time-sharing System)namespace 提供了主機名與域名的隔離,這樣每個 docke 容器就可以擁有獨立的主機名和域名了,在網(wǎng)絡(luò)上可以被視為一個獨立的節(jié)點,而非宿主機上的一個進程。

docker 中,每個鏡像基本都以自身所提供的服務(wù)名稱來命名鏡像的 hostname,且不會對宿主機產(chǎn)生任何影響,其原理就是使用了 UTS namespace。

2、IPC namespace

進程間通信 (Inter-Process Communication,IPC) 涉及的 IPC 資源包括常見的信號量、消息隊列和共享內(nèi)存。申請 IPC 資源就申請了一個全局唯一的 32 位 ID,所以 IPC namespace 中實際上包含了系統(tǒng) IPC 標(biāo)識符以及實現(xiàn) POSIX 消息隊列的文件系統(tǒng)。在同一個 IPC namespace 下的進程彼此可見,不同 IPC namespace 下的進程則互相不可見。

目前使用 IPC namespace 機制的系統(tǒng)不多,其中比較有名的有 PostgreSQL。Docker 當(dāng)前也使用 IPC namespace 實現(xiàn)了容器與宿主機、容器與容器之間的 IPC 隔離。

3、PID namespace

PID namespace 隔離非常實用,它對進程 PID 重新標(biāo)號,即兩個不同 namespace 下的進程可以有相同的 PID。每個 PID namespace 都有自己的計數(shù)程序。內(nèi)核為所有的 PID namespace 維護了一個樹狀結(jié)構(gòu),最頂層的是系統(tǒng)初始時創(chuàng)建的,被稱為 root namespace,它創(chuàng)建的心 PID namespace 被稱為 child namespace(樹的子節(jié)點),而原先的 PID namespace 就是新創(chuàng)建的 PID namespace 的 parent namespace(樹的父節(jié)點)。通過這種方式,不同的 PID namespace 會形成一個層級體系。所屬的父節(jié)點可以看到子節(jié)點中的進程,并可以通過信號等方式對子節(jié)點中的進程產(chǎn)生影響。反過來,子節(jié)點卻不能看到父節(jié)點 PID namespace 中的任何內(nèi)容,由此產(chǎn)生如下結(jié)論。

  • 每個 PID namespace 中的第一個進程 “PID 1”,都會像全通 Linux 中的 init 進程一樣擁有特權(quán),其特殊作用。
  • 一個 namespace 中的進程,不可能通過 kill 或 ptrace 影響父節(jié)點或者兄弟節(jié)點中的進程,因為其他幾點的 PID 在這個 namespace 沒有任何意義。
  • 如果你在新的 PID namespace 中重新掛載 / proc 文件系統(tǒng),會發(fā)現(xiàn)其下只顯示同屬一個 PID namespace 中的其他進程。
  • 在 root namespace 中看到所有的進程,并且遞歸包含所有子節(jié)點中的進程。到這里,讀者可能已經(jīng)聯(lián)想到了一種在 Docker 外部監(jiān)控運行程序的方法了,就是監(jiān)控 Docker daemon 所在的 PID namespace 下的所有進程及子進程,在進行篩選即可。

4、mount namespace

mount namespace 通過隔離文件系統(tǒng)掛載點對隔離文件系統(tǒng)提供支持,它是歷史上第一個 Linux namespace,所以標(biāo)示位比較特殊,就是CLONE_NEWNS。隔離后,不同的 mount namespace 中的文件結(jié)構(gòu)發(fā)生變化也互不影響。也可以通過 / proc/[pid]/mounts 查看到所有掛載在當(dāng)前 namespace 中的文件系統(tǒng),還可以通過 / proc/[pid]/mountstats 看到 mount namespace 中文件設(shè)備的統(tǒng)計信息,包括掛載文件的名字、文件系統(tǒng)的類型、掛載位置等。

進程在創(chuàng)建 mount namespace 時,會把當(dāng)前的文件結(jié)構(gòu)復(fù)制給新的 namespace。新 namespace 中的所有 mount 操作都只影響自身的文件系統(tǒng),對外界不會產(chǎn)生任何影響。這種做法非常嚴(yán)格的實現(xiàn)了隔離,但對某些狀況可能并不適用。比如父節(jié)點 namespace 中的進程掛載了一張 CD-ROM,這時子節(jié)點 namespace 復(fù)制的目錄結(jié)構(gòu)是無法自動掛載上這張 CD-ROM 的,因為這種操作會影響到父節(jié)點的文件系統(tǒng)。

一個掛載狀態(tài)可能為以下一種:

  • 共享掛載
  • 從屬掛載
  • 共享 / 從屬掛載
  • 私有掛載
  • 不可綁定掛載

傳播事件的掛載對象稱為共享掛載;接收傳播事件的掛載對象稱為從屬掛載;同時兼有前述兩者特征的掛載對象為共享 / 從屬掛載;既不傳播也不接受事件的掛載對象稱為私有掛載;另一種特殊的掛載對象稱為不可綁定掛載,它們與私有掛載相似,但不允許執(zhí)行綁定掛載,即創(chuàng)建 mount namespace 時這塊文件對象不可被復(fù)制。

5、netword namespace

network namespace 主要提供了關(guān)于網(wǎng)絡(luò)資源的隔離,包括網(wǎng)絡(luò)設(shè)備、IPv4 和 IPv6 協(xié)議棧、IP 路由表、防火墻、/proc/net 目錄、/sys/class/net 目錄、socket 等。一個物理的網(wǎng)絡(luò)設(shè)備最多存在于一個 network namespace 中,可以通過創(chuàng)建 veth pair(虛擬網(wǎng)絡(luò)設(shè)備對:有兩端,類似管道,如果數(shù)據(jù)從一端傳入另一端也能接受,反之亦然) 在不同的 network namespace 間創(chuàng)建通道,以達到通信目的。

也許你會好奇,在建立起 veth pair 之前,新舊 namespace 該如何通信呢?答案是pipe(管道)。以 Docker daemon 啟動容器的過程為例,假設(shè)容器內(nèi)初始化的進程稱為 init。Docker daemon 在宿主機上負責(zé)創(chuàng)建這個 veth pair,把一段綁定到 docker0 網(wǎng)橋上,另一端介入新建的 network namespace 進程中。這個過程執(zhí)行期間,Docker daemon 和 init 就通過 pipe 進行通信。具體來說,就是在 Docker deamon 完成 veth pair 的創(chuàng)建之前,init 在管道的另一端循環(huán)等待,直到管道另一端傳來 Docker daemon 關(guān)于 veth 設(shè)備的信息,并關(guān)閉管道。init 才結(jié)束等待的過程,并把它的 “eth0” 啟動起來。

與其他 namespace 類似,對 network namespace 的使用其實就是在創(chuàng)建的時候添加 CLONE_NEWNET 標(biāo)識符位。

6、user namespace

user namespace 主要隔離了安全相關(guān)的標(biāo)識符 (identifier) 和屬性 (attribute),包括用戶 ID、用戶組 ID、root 目錄、key(指密鑰) 以及特殊權(quán)限。通俗地講,一個普通用戶的進程通過 clone()創(chuàng)建的新進程在新 user namespace 中可以擁有不同的用戶和用戶組。這意味著一個進程在容器外屬于一個沒有特權(quán)的普通用戶,但是它創(chuàng)建的容器進程卻屬于擁有所有權(quán)限的超級用戶,這個技術(shù)為容器提供了極大的自由。

user namespace 時目前的 6 個 namespace 中最后一個支持的,并且直到 linux 內(nèi)核 3.8 版本的時候還未完全實現(xiàn) (還有部分文件系統(tǒng)不支持)。user namespace 實際上并不算完全成熟,很多發(fā)行版擔(dān)心安全問題,在編譯內(nèi)核的時候并未開啟 USER_NS。Docker 在 1.10 版本中對 user namespace 進行了支持。只要用戶在啟動 Docker daemon 的時候制定了–user-remap,那么當(dāng)用戶運行容器時,容器內(nèi)部的 root 用戶并不等于宿主機的 root 用戶,而是映射到宿主機上的普通用戶。

Docker 不僅使用了 user namespace,還使用了在 user namespace 中涉及的 Capability 機制。從內(nèi)核 2.2 版本開始,Linux 把原來和超級用戶相關(guān)的高級權(quán)限分為不同的單元,稱為 Capability。這樣管理員就可以獨立的對特定的 Capability 進行使用或禁止。Docker 同時使用 namespace 和 Capability,這很大程度上加強了容器的安全性。

這些似乎都是 docker 相關(guān)的基礎(chǔ)性概念,過去也許并非沒有看過,但都一帶而過沒有留下印象,若非今日時間問題這個機緣,恐怕自己也還一直不懂得這些原理,有時候?qū)W習(xí)就是如此,要看緣分。重要的是,如果緣分來了,不要錯失!

三、如何單獨更改容器時間

后來經(jīng)過朋友分享,發(fā)現(xiàn)可以通過曲線救國的方式更改容器的時間。

在github上有一個libfaketime項目,我們可以使用LD_PRELOAD這個環(huán)境變量使date連接這個項目編譯的庫來fake(欺騙)應(yīng)用,達到修改docker容器時間的目的。

1、先導(dǎo)試驗

通過如下操作可以獲得依賴庫:

$ git clone https://github.com/wolfcw/libfaketime.git
$ cd libfaketime/src/
$ make install

編譯之后,將會獲得對應(yīng)的庫文件。

src/libfaketime.so.1

同時也在系統(tǒng)之中生成了對應(yīng)的文件。
/usr/local/lib/faketime/libfaketime.so.1

接著來啟動一個容器操作一下看看。

docker run -itd --name aa 192.168.112.69/public/jdk:1.8
docker cp src/libfaketime.so.1 aa:/usr/local/lib

然后進入到容器之中引用并更改時間。

sh-4.2# date
Thu Jun 20 15:35:18 CST 2019

sh-4.2# export LD_PRELOAD=/usr/local/lib/libfaketime.so.1 FAKETIME="-10d"

sh-4.2# date
Mon Jun 10 15:35:39 CST 2019

這樣就實現(xiàn)了容器時間變更,而宿主機時間并不會變。

但是我個人測試的情況是,進入容器之后的確可以實現(xiàn),但是退出容器重新進入之后,時間就又回到與宿主機一致的了。

所以如上操作是有一些問題的,問題不在于操作的過程有問題,而在于那個環(huán)境變量出了問題,當(dāng)前聲明沒有問題,但是從新進入容器之后,聲明的環(huán)境變量就沒有了,這也是退出容器重新進入之后時間變成當(dāng)前時間的原因。接下來將配置真正可以更改容器時間的方案。

2、正式操作

現(xiàn)在只是把流程步驟記錄一下,實際生產(chǎn)應(yīng)用的話,僅作為效果參考,不代表實際生產(chǎn)鏡像配置最終效果

準(zhǔn)備內(nèi)容:

$ ls
Dockerfile      libfaketime.tar     faketime.sh

其中 libfaketime.tar就是我下載的源碼打的包。 查看對應(yīng)內(nèi)容:

faketime.sh

#!/bin/bash
targetTime="$1"
if [[ ${targetTime} == "" ]];then
  echo "need a absolute time. eg: 2020-12-24 20:30:00"
  exit;
fi
current=`date +%s`
target=`date -d "$targetTime" +%s`
let time=($target-$current)
if [[ $time -gt 0 ]];then
  time="+$time"
fi
echo $time
echo $time > /etc/faketimerc

Dockerfile

# Dockerizing CentOS7: Dockerfile for building CentOS images
#需要一個基礎(chǔ)鏡像,這里從國內(nèi)的daocloud下載,速度比較快。
FROM       daocloud.io/library/centos:centos7.4.1708

#維護者
MAINTAINER eryajf <Linuxlql@163.com>

ADD libfaketime.tar /opt
ADD faketime.sh /mnt

RUN yum -y install gcc automake autoconf libtool make gcc-c++ && cd /opt/libfaketime/src && make install && touch /etc/faketime

ENV TZ "Asia/Shanghai"
ENV LD_PRELOAD "/usr/local/lib/faketime/libfaketime.so.1" #重要的就是這個聲明,是他,成就了時間穿梭的效果

構(gòu)建一下:

$ docker build -t test .

啟動驗證:

$ docker run -itd --name test test
$ docker exec -it test bash

容器內(nèi)驗證:

[root@c23c65999a52 mnt]# date
Wed Aug  7 11:09:13 CST 2019

[root@c23c65999a52 mnt]# ./faketime.sh "2020-12-24 20:30:00"
+43696422

[root@c23c65999a52 mnt]# date
Thu Dec 24 20:30:27 UTC 2020

退出容器重新進入,時間也是更改之后的時間了,如果想要讓時間變成當(dāng)前時間,可以刪除 /etc/faketimerc文件,即可。

[root@443422a71e6e /]# rm -f /etc/faketimerc
[root@443422a71e6e /]# date
Wed Aug  7 11:11:05 CST 2019

如此就集成了更改容器時間的功能了,這個功能,可以集成到基礎(chǔ)容器當(dāng)中去。

3、終稿版本

最終個人自用的基礎(chǔ)鏡像小操作,首先把上邊編譯好的庫文件拷貝出來,然后利用如下dockerfile構(gòu)建一個基礎(chǔ)鏡像。

$ cat Dockerfile
# Dockerizing CentOS7: Dockerfile for building CentOS images
#需要一個基礎(chǔ)鏡像,這里從國內(nèi)的daocloud下載,速度比較快。
FROM       daocloud.io/library/centos:centos7.4.1708

#維護者
MAINTAINER eryajf <Linuxlql@163.com>

ADD libfaketime.so.1 /usr/local/lib/
ADD faketime /usr/local/bin

RUN yum -y install lrzsz wget curl vim net-tools rsync git && yum clean all
ENV TZ "Asia/Shanghai"
ENV LD_PRELOAD "/usr/local/lib/libfaketime.so.1"

直接把庫文件放在系統(tǒng)中,然后也把更改時間的腳本放到環(huán)境變量下,如此以來,直接運行faketime命令即可。

docker build -t registry.cn-hangzhou.aliyuncs.com/eryajf/centos:7.5 .
docker push registry.cn-hangzhou.aliyuncs.com/eryajf/centos:7.5

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • docker5 全功能harbor倉庫搭建過程

    docker5 全功能harbor倉庫搭建過程

    Harbor是構(gòu)建企業(yè)級私有docker鏡像的倉庫的開源解決方案,本文給大家分享docker5 全功能harbor倉庫搭建過程,感興趣的朋友一起看看吧
    2021-06-06
  • 詳解如何解決docker容器無法通過IP訪問宿主機問題

    詳解如何解決docker容器無法通過IP訪問宿主機問題

    這篇文章主要介紹了詳解如何解決docker容器無法通過IP訪問宿主機問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • Docker部署FastDFS的實現(xiàn)方法

    Docker部署FastDFS的實現(xiàn)方法

    這篇文章主要介紹了Docker部署FastDFS的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Docker 查詢、停止、刪除和重啟容器的詳細過程

    Docker 查詢、停止、刪除和重啟容器的詳細過程

    這篇文章主要介紹了Docker 查詢、停止、刪除和重啟容器,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-02-02
  • 一文搞定Docker安裝ElasticSearch的過程

    一文搞定Docker安裝ElasticSearch的過程

    通過本文可以幫助大家快速學(xué)習(xí)Docker安裝ElasticSearch的過程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-08-08
  • Docker安裝Elasticsearch的實現(xiàn)示例

    Docker安裝Elasticsearch的實現(xiàn)示例

    本文主要介紹了在Docker環(huán)境下安裝和ockerSearch、Kibana及IK分詞器的步驟,并并包括配置項設(shè)置D以及常用命令使用方法,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-04-04
  • docker image tag為什么出現(xiàn)none的原因及解決

    docker image tag為什么出現(xiàn)none的原因及解決

    當(dāng)我們使用docker加載新的鏡像時,有時候會發(fā)現(xiàn)Repository和Tag名稱都為none的情況,這通常是由于沒有指定正確的標(biāo)簽名稱或者倉庫名稱所導(dǎo)致的,本文主要介紹了docker image tag為什么出現(xiàn)none的原因及解決,感興趣的可以了解一下
    2023-10-10
  • Docker磁盤滿了的高效又安全清理方案小結(jié)

    Docker磁盤滿了的高效又安全清理方案小結(jié)

    明明代碼邏輯沒問題,部署時卻頻頻報錯,排查半天發(fā)現(xiàn)是服務(wù)器磁盤被占滿了,下面我們就來看看解決思路,希望可以幫助大家快速釋放磁盤空間
    2025-10-10
  • 使用docker環(huán)境變量動態(tài)配置nginx的問題小結(jié)

    使用docker環(huán)境變量動態(tài)配置nginx的問題小結(jié)

    這篇文章主要介紹了使用docker環(huán)境變量動態(tài)配置nginx,整個方案,采用的是通過docker run -e xxxx=xxx先往容器注入環(huán)境變量,然后進一步通過envsubst指令將環(huán)境變量寫入到具體的文件當(dāng)中,實現(xiàn)動態(tài)配置文件內(nèi)容,需要的朋友可以參考下
    2022-06-06
  • Docker容器化spring boot應(yīng)用詳解

    Docker容器化spring boot應(yīng)用詳解

    本篇文章主要介紹了Docker容器化spring boot應(yīng)用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04

最新評論

修文县| 衢州市| 博客| 凤阳县| 光山县| 舟曲县| 德昌县| 会昌县| 金门县| 集安市| 石台县| 翁牛特旗| 思南县| 綦江县| 盐亭县| 周至县| 高台县| 桃园县| 龙泉市| 望城县| 北安市| 固原市| 基隆市| 德昌县| 民乐县| 万荣县| 兴文县| 清徐县| 东源县| 搜索| 重庆市| 昭通市| 乌兰浩特市| 梁平县| 民勤县| 大方县| 英德市| 舟山市| 巩义市| 鹤壁市| 洪江市|