1. 程式人生 > >探討Docker容器中修改系統變數的方法[轉]

探討Docker容器中修改系統變數的方法[轉]

探討完Docker對共享記憶體狀態持久化的支援狀況後,我將遺留產品build到一個pre-production image中,測試啟動是否OK。很顯然,我過於樂觀了,Docker之路並不平坦。我收到了shmget報出的EINVAL錯誤碼,提示引數非法。 shmget的manual對EINVAL錯誤碼的說明如下:

EINVAL:
A new segment was to be created and size < SHMMIN or size > SHMMAX, or no new segment was to be created, a segment with given key existed, but size is greater than the size of that segment.

顯然我們要建立的shared memory的size很可能大於SHMMAX這個系統變量了。那麼一個從base image創建出的容器中的系統變數到底是什麼值呢?我們來檢視一下,我們基於”centos:centos6”啟動一個Docker容器,並檢查其中的 系統變數值設定:

$ sudo docker run -it “centos:centos6” /bin/bash
bash-4.1# cat /proc/sys/kernel/shmmax
33554432
bash-4.1# sysctl -a|grep shmmax
kernel.shmmax = 33554432

可以看出預設情況下,當前容器中root賬號看到的shmmax值我33554432, 我的程式要建立的shm size的確要大於這個值,報出EINVAL錯誤也就無可厚非了。我嘗試按照物理機上的方法臨時修改一下該值:

bash-4.1# echo 68719476736 > /proc/sys/kernel/shmmax
bash: /proc/sys/kernel/shmmax: Read-only file system

/proc/sys/kernel/shmmax居然是隻讀的,無法修改。

我又嘗試修改/etc/sysctl.conf這個持久化系統變數的地方,但開啟/etc/sysctl.conf檔案,我發現我又錯了,這 個檔案中shmmax的值如下:

Controls the maximum shared segment size, in bytes

kernel.shmmax = 68719476736

/etc/sysctl.conf檔案 中的系統變數shmmax的值是68719476736,而系統當前的實際值則是33554432,難道是/etc /sysctl.conf中的值沒有生效,於是我手工重新載入一次該檔案:

-bash-4.1# sysctl -p
error: “Read-only file system” setting key “net.ipv4.ip_forward”
error: “Read-only file system” setting key “net.ipv4.conf.default.rp_filter”
error: “Read-only file system” setting key “net.ipv4.conf.default.accept_source_route”
error: “Read-only file system” setting key “kernel.sysrq”
error: “Read-only file system” setting key “kernel.core_uses_pid”
error: “net.ipv4.tcp_syncookies” is an unknown key
error: “net.bridge.bridge-nf-call-ip6tables” is an unknown key
error: “net.bridge.bridge-nf-call-iptables” is an unknown key
error: “net.bridge.bridge-nf-call-arptables” is an unknown key
error: “Read-only file system” setting key “kernel.msgmnb”
error: “Read-only file system” setting key “kernel.msgmax”
error: “Read-only file system” setting key “kernel.shmmax”
error: “Read-only file system” setting key “kernel.shmall”

我得到了和之前類似的錯誤結果:只讀檔案系統,無法修改。於是乎兩個問題縈繞在我的面前:
1、為什麼容器內當前系統變數值與sysctl.conf中的不一致?
2、為什麼無法修改當前系統變數值?

在翻閱了Stackoverflow, github docker issues後,我得到了的答案如下:

1、Docker的base image做的很精簡,甚至都沒有init程序,原本在OS啟動時執行生效系統變數的過程(sysctl -p)也給省略了,導致這些系統變數依舊保留著kernel預設值。以CentOs為例,在linux kernel boot後,init都會執行/etc/rc.d/rc.sysinit,後者會載入/etc/sysctl.conf中的系統變數值。下面是 CentOs5.6中的rc.sysinit程式碼摘錄:

… …

Configure kernel parameters

update_boot_stage RCkernelparam
sysctl -e -p /etc/sysctl.conf >/dev/null 2>&1
… …

2、Docker容器中的系統變數在non-priviledged模式下目前(我使用的時docker 1.2.0版本)就無法修改,這 和resolv.conf、hosts等檔案對映到宿主機對應的檔案有不同。

$ mount -l
…. ….
/dev/mapper/ubuntu–Server–14–vg-root on /etc/resolv.conf type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/mapper/ubuntu–Server–14–vg-root on /etc/hostname type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/mapper/ubuntu–Server–14–vg-root on /etc/hosts type ext4 (rw,relatime,errors=remount-ro,data=ordered)
… …

那麼我們該如何修改系統變數值來滿足遺留產品的需求呢?

一、使用–privileged選項

我們使用–privileged這個特權選項來啟動一個基於centos:centos6的新容器,看看是否能對shmmax這樣的系統變數值 進行修改:

$ sudo docker run -it –privileged “centos:centos6” /bin/bash
bash-4.1# cat /proc/sys/kernel/shmmax
33554432
bash-4.1# echo 68719476736 > /proc/sys/kernel/shmmax
bash-4.1# cat /proc/sys/kernel/shmmax
68719476736
bash-4.1# sysctl -p
net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
… …
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296

可以看出,通過–privileged選項,容器獲得了額外的特權,並且可以對系統變數的值進行修改了。不過這樣的修改是不能儲存在容器裡的, 我們stop 容器,再重啟該容器就能看出來:

sudodockerstart3e22d65a7845 sudo docker attach 3e22d65a7845
bash-4.1# cat /proc/sys/kernel/shmmax
33554432

shmmax的值在容器重啟後又變回了原先的那個預設值。不過重啟後的容器依舊具有privileged的特權,我們還可以重新手工執行命令對系 統變數進行修改:

bash-4.1# echo 68719476736 > /proc/sys/kernel/shmmax
bash-4.1# cat /proc/sys/kernel/shmmax
68719476736

但即便這樣,也無法滿足我們的需求,我們總不能每次都在容器中手工執行系統變數值修改的操作吧。privileged選項的能力能否帶到 image中呢?答案是目前還不能,我們無法在build image時通過privileged選項修改系統變數值。

這樣一來,我們能做的只有把產品啟動與系統變數值修改放在一個指令碼中了,並將該指令碼作為docker 容器的cmd命令來執行,比如我們構建一個Dockerfile:

FROM centos:centos6
MAINTAINER Tony Bai [email protected]
RUN yum install python-setuptools -y
RUN easy_install supervisor
RUN mkdir -p /var/log/supervisor
COPY ./supervisord.conf /etc/supervisord.conf
COPY ./start.sh /bin/start.sh
RUN chmod +x /bin/start.sh
CMD [“/bin/start.sh]

//start.sh
sysctl -p
/usr/bin/supervisord

這樣,start.sh在supervisord啟動前將系統變數值重新載入,而supervisord後續啟動的程式就可以看到這些新系統變數 的值了。不過別忘了利用這個image啟動容器時要加上–priviledged選項,否則容器啟動就會失敗。

二、使用phusion/baseimage

前面說過/etc/sysctl.conf中的值沒有生效是因為docker官方提供的centos:centos6把init程序的初始化過程給精 簡掉了。phusion/baseimage是目前docker registery上僅次於ubuntu和centos兩個之後的base image,其提供了/sbin/my_init這個init程序,用於在container充當init程序的角色。那麼my_init是否可以用於執行sysctl -p呢?我們試驗一下:

我們先pull這個base image下來:sudo docker pull phusion/baseimage。pull成功後,我們先基於“phusion/baseimage”啟動一個容器做一些explore工作:

$ sudo docker run -i -t “phusion/baseimage”
* Running /etc/my_init.d/00_regen_ssh_host_keys.sh…
No SSH host key available. Generating one…
Creating SSH2 RSA key; this may take some time …
Creating SSH2 DSA key; this may take some time …
Creating SSH2 ECDSA key; this may take some time …
Creating SSH2 ED25519 key; this may take some time …
invoke-rc.d: policy-rc.d denied execution of restart.
* Running /etc/rc.local…
* Booting runit daemon…
* Runit started as PID 100

通過nsenter進去,檢視一下/sbin/my_init的原始碼,我們發現這是一個python指令碼,不過從頭到尾瀏覽一遍,沒有發現sysctl載入/etc/sysctl.conf系統變數的操作。

不過,phusion文件中說my_init可以在初始化過程中執行/etc/my_init.d下的指令碼。那是不是我們將一個執行sysctl -p的指令碼放入/etc/my_init.d下就可以實現我們的目的了呢?試試。

我們編寫一個指令碼:load_sys_varibles.sh

!/bin/sh

sysctl -p > init.txt

下面是製作image的Dockerfile:

FROM phusion/baseimage:latest
MAINTAINER Tony Bai [email protected]
RUN echo “kernel.shmmax = 68719476736” >> /etc/sysctl.conf
RUN mkdir -p /etc/my_init.d
ADD load_sys_varibles.sh /etc/my_init.d/load_sys_varibles.sh
RUN chmod +x /etc/my_init.d/load_sys_varibles.sh
CMD [“/sbin/my_init”]

phusion/baseimage是基於ubuntu的OS,其sysctl.conf預設情況下沒啥內容,所以我們在Dockerfile中向這個檔案寫入我們需要的系統變數值。構建image並啟動容器:

$ sudo docker build -t “myphusion:v1” ./
Sending build context to Docker daemon 13.12 MB
Sending build context to Docker daemon
Step 0 : FROM phusion/baseimage:latest
—> cf39b476aeec
Step 1 : MAINTAINER Tony Bai [email protected]
—> Using cache
—> d0e9b51a3e4f
Step 2 : RUN echo “kernel.shmmax = 68719476736” >> /etc/sysctl.conf
—> Using cache
—> 2c800687cc83
Step 3 : RUN mkdir -p /etc/my_init.d
—> Using cache
—> fe366eea5eb4
Step 4 : ADD load_sys_varibles.sh /etc/my_init.d/load_sys_varibles.sh
—> a641bb595fb9
Removing intermediate container c381b9f001c2
Step 5 : RUN chmod +x /etc/my_init.d/load_sys_varibles.sh
—> Running in 764866552f25
—> eae3d7f1eac5
Removing intermediate container 764866552f25
Step 6 : CMD [“/sbin/my_init”]
—> Running in 9ab8d0b717a7
—> 8be4e7b6b174
Removing intermediate container 9ab8d0b717a7
Successfully built 8be4e7b6b174

$ sudo docker run -it “myphusion:v1”
* Running /etc/my_init.d/00_regen_ssh_host_keys.sh…
No SSH host key available. Generating one…
Creating SSH2 RSA key; this may take some time …
Creating SSH2 DSA key; this may take some time …
Creating SSH2 ECDSA key; this may take some time …
Creating SSH2 ED25519 key; this may take some time …
invoke-rc.d: policy-rc.d denied execution of restart.
* Running /etc/my_init.d/load_sys_varibles.sh…
sysctl: setting key “kernel.shmmax”: Read-only file system
* /etc/my_init.d/load_sys_varibles.sh failed with status 255

* Killing all processes…

唉,還是老問題!即便是在my_init中執行,依舊無法逾越Read-only file system,檢視Phusion/baseimage的Dockerfile才知道,它也是From ubuntu:14.04的,根不變,上層再怎麼折騰也沒用。

換一種容器run方法吧,加上–privileged:

$ sudo docker run -it –privileged “myphusion:v1”
* Running /etc/my_init.d/00_regen_ssh_host_keys.sh…
No SSH host key available. Generating one…
Creating SSH2 RSA key; this may take some time …
Creating SSH2 DSA key; this may take some time …
Creating SSH2 ECDSA key; this may take some time …
Creating SSH2 ED25519 key; this may take some time …
invoke-rc.d: policy-rc.d denied execution of restart.
* Running /etc/my_init.d/load_sys_varibles.sh…
* Running /etc/rc.local…
* Booting runit daemon…
* Runit started as PID 102

這回靈光了。enter到容器裡看看設定的值是否生效了:

[email protected]:~#cat /proc/sys/kernel/shmmax
68719476736

結果如預期。這樣來看phusion/baseimage算是為sysctl -p載入系統變數值提供了一個便利,但依舊無法脫離–privileged,且依舊無法在image中持久化這個設定。

在Docker github的issue中有人提出建議在Dockerfile中加入類似RUNP這樣的帶有特權的指令語法,但不知何時才能在Docker中加入這一功能。

總而言之,基於目前docker官網提供的base image,我們很難找到特別理想的修改系統變數值的方法,除非自己製作base image,這個還沒嘗試過,待後續繼續研究。

相關推薦

探討Docker容器修改系統變數方法[]

探討完Docker對共享記憶體狀態持久化的支援狀況後,我將遺留產品build到一個pre-production image中,測試啟動是否OK。很顯然,我過於樂觀了,Docker之路並不平坦。我收到了shmget報出的EINVAL錯誤碼,提示引數非法。 sh

Eclipse修改作者變數${user} ()

在使用Eclipse編寫Java程式碼時,自動生成的註釋資訊都是預設是使用的當前登入系統使用者名稱: /*** @author administrator*/ 如果我們想修改成我們自己的名字怎麼辦呢? 以下介紹的三種方法也可以應用在MyEclipse中 方法一. 修改Ecli

Docker容器部署靜態網頁的方法教程

tin uri ash led att bin get acf code 步驟:1.創建映射端口的交互式容器docker run -p 80 --name web -i -t daocloud.io/ubuntu /bin/bash2.安裝Nginxapt-get inst

Linux修改環境變數及生效方法

檢視PATH:echo $PATH 以新增mongodb server為列 修改方法一: export PATH=/usr/local/mongodb/bin:$PATH //配置完後可以通過echo $PATH檢視配置結果。 生效方法:立即生效 有效期限:臨時改變,只能在當

linux修改環境變數之後導致系統崩潰(使用者所有命令不能使用)的解決辦法

今天在虛擬機器裡自己瞎倒騰,利用vim修改了/.bashrc中的環境變數,結果,悲劇了,當前使用者下出了cd命令有效,其他一切命令都不能夠正常使用了,找了好久終於找到了解決的辦法,現在記錄下來: 我們修改了環境變數之後只是修改當前使用者的環境變數,而對於系統的其他使用者而言

Docker容器執行Ubuntu系統

原址只習慣用Centos系統,但是有些軟體編譯安裝很麻煩不方便,但是呢在Ubuntu中就變得容易方便,所以我打算用docker執行Ubuntu系統彌補Centos短板和不足之處;專案地址:https://hub.docker.com/_/ubuntu/1、安裝Ubuntu系統

Linux系統CentOS 7修改修改系統時區方法

linux在安裝的時候如果時區選擇錯誤,可以在系統安裝完成之後修改。系統時間執行著也會有偏差,需要對時間進行實時同步,方法如下:1、用date命令檢視系統當前時間,發現和北京時間有一定的誤差(當前時間為

Docker容器運行.Net Core web Api項目

c99 images sof 以及 store .com 查看 .html microsoft 安裝Docker環境 參考本人這篇《CentOS 7 下Docker的安裝》文章進行安裝以及環境配置,這裏不做贅述。 通過.NetCore開發WebApi項目 1. 創建.Net

Docker 容器運行應用程序

ges 文件中 機制 計算 http cannot info 應用 png 案例說明 運行 3 個容器,實現對網站的監控。 三個容器的說明: 容器 web: 創建自 nginx 映像,使用 80 端口,運行於後臺,實現 web 服務。 容器 mailer: 該容

docker容器安裝vim

docker容器中安裝vim在使用docker容器時,有時候裏邊沒有安裝vim,敲vim命令時提示說:vim: command not found,這個時候就需要安裝vim,可是當你敲apt-get install vim命令時,提示: Reading package lists... Done

docker容器啟動service服務 Failed to get D-Bus connection: Operation not permitted

docker容器中啟動service服務 failed to get d-bus connection: operation not permitted解決方案:啟動時設置參數 --privileged使用該參數,container內的root擁有真正的root權限。否則,container內的root只是

docker容器沒有vi

最新 alt .com blog docker容器 作用 容器 sta 索引 在使用docker容器時,輸入vim命令時提示說:vim: command not found,這個時候就需要安裝vim,可是當你敲apt-get install vi命令時,提示如下:這時就需要

隔離 docker 容器的用戶

pre 然而 ping htm spa 用戶 nic exe 完美 筆者在前文《理解 docker 容器中的 uid 和 gid》介紹了 docker 容器中的用戶與宿主機上用戶的關系,得出的結論是:docker 默認沒有隔離宿主機用戶和容器中的用戶。如果你已經了解了 Li

Jenkins外掛之 Docker-Plugin 將slave執行在docker容器

Jenkins外掛名稱 Docker plugin This plugin integrates Jenkins with Docker This plugin allows slaves to be dynamically provisioned using Docker. 外掛文

Javastatic(靜態變數/方法)的優缺點

static關鍵字宣告的變數或方法稱為靜態變數/方法 靜態static變數/方法在類載入的過程中被初始化,在記憶體中只存在一份,所以可以把它當作是全域性變數/方法。 優點 屬於類級別的,不需要建立物件就可以直接使用. 全域性唯一,記憶體中唯一,靜態變數

.NetCore下使用IdentityServer4 & JwtBearer認證授權在CentOS Docker容器執行遇到的坑及填坑

今天我把WebAPI部署到CentOS Docker容器中執行,發現原有在Windows下允許的JWTBearer配置出現了問題 在Window下我一直使用這個配置,沒有問題 services.AddAuthentication(JwtBearerDefaults.AuthenticationSc

linux docker容器安裝maven nexus倉庫

1.docker安裝,參考上一篇rancher2.0搭建簡單的k8s叢集 2.建立資料夾:/usr/local/work/maven 3.執行docker,拉取nexus映象。 docker search nexus; #拉取nexus映象 docker pull sonatyp

docker容器的Tomcat遠端debug

進入Tomcat容器 docker exec -it containerId bash containerId: Tomcat容器的id 修改Tomcat的catalina.sh檔案 在catalina.sh中新增如下程式碼: CATALINA_OPTS="-X

如何把 Java Web 應用放在 docker 容器執行

本文適合 docker 零基礎,且希望使用 docker 執行 Java Web 應用的人士。因為是傻瓜教程,這裡沒有使用 docker 的高階功能,本教程旨在用最簡單方法實現目標。 安裝 docker Docker 的安裝資原始檔存放在Amazon,由於國內特殊的網路環境,安裝時,會間歇

解決:bash: vim: command not found、docker 容器不識別 vi / vim 、docker 容器安裝 vim

1. 在 Docker 容器中編輯檔案,報錯如下: bash: vim: command not found 2.  安裝 vim : apt-get install vim  執行完成後報錯: Reading package lists... D