首页
About Me
Search
1
linuxea:gitlab-ci之docker镜像质量品质报告
49,485 阅读
2
linuxea:如何复现查看docker run参数命令
23,755 阅读
3
Graylog收集文件日志实例
18,638 阅读
4
linuxea:jenkins+pipeline+gitlab+ansible快速安装配置(1)
18,438 阅读
5
git+jenkins发布和回滚示例
18,235 阅读
ops
Openppn
Sys Basics
rsync
Mail
NFS
Other
Network
HeartBeat
server 08
Code
Awk
Shell
Python
Golang
vue
virtualization
KVM
Docker
openstack
Xen
kubernetes
kubernetes-cni
Service Mesh
Data
Mariadb
PostgreSQL
MongoDB
Redis
MQ
Ceph
TimescaleDB
kafka
surveillance system
zabbix
ELK Stack/logs
Open-Falcon
Prometheus
victoriaMetrics
Web
apache
Tomcat
Nginx
自动化
Puppet
Ansible
saltstack
Proxy
HAproxy
Lvs
varnish
更多
互联咨询
最后的净土
软件交付
持续集成
gitops
devops
登录
Search
标签搜索
kubernetes
docker
zabbix
Golang
mariadb
持续集成工具
白话容器
elk
linux基础
nginx
dockerfile
Gitlab-ci/cd
最后的净土
基础命令
gitops
jenkins
docker-compose
Istio
haproxy
saltstack
marksugar
累计撰写
667
篇文章
累计收到
111
条评论
首页
栏目
ops
Openppn
Sys Basics
rsync
Mail
NFS
Other
Network
HeartBeat
server 08
Code
Awk
Shell
Python
Golang
vue
virtualization
KVM
Docker
openstack
Xen
kubernetes
kubernetes-cni
Service Mesh
Data
Mariadb
PostgreSQL
MongoDB
Redis
MQ
Ceph
TimescaleDB
kafka
surveillance system
zabbix
ELK Stack/logs
Open-Falcon
Prometheus
victoriaMetrics
Web
apache
Tomcat
Nginx
自动化
Puppet
Ansible
saltstack
Proxy
HAproxy
Lvs
varnish
更多
互联咨询
最后的净土
软件交付
持续集成
gitops
devops
页面
About Me
搜索到
26
篇与
的结果
2019-01-21
linuxea:白话容器之Registry与Harbor的构建和使用 (26)
Registry用于保存docker镜像,包括镜像的层次结构和元数据,用户可以自己创建Registry,也可以使用官方的dockerhub,这些Registry支持第三方注册。但是这些Registry在互联网上,使用时候下载的速度不会再快,并且在实际使用中,有多数进行下载,宽带也会成为一个问题。为了达到最快的拉取目的,我们就需要自己构建Registry。Private RegistryRegistry主要用于托管镜像,Registry默认是https的,如果要使用http就需要特别的指定。为了能够使我们快速构建Registry,dockre提供了一个项目distribution,安装即可。而在docker官方已经将Registry作为镜像,由此,我们直接使用Registry镜像就可以运行Registry。Registry主要用于托管镜像,而Registry本身也是托管在容器中,容器的文件系统会随着容器的终止而删除的,Registry运行在容器后这些镜像是不能存放在容器中的,我们将它存储到存储卷内,如:网络存储。当然也可以在本地存放。这种方式很简单就可以运行起来一个Registry。如果不想使用这种方式,也可以使用docker-distribution安装docker-distribution[root@www-linuxea ~]$ yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo[root@www-linuxea ~]$ yum install docker-distribution -y[root@www-linuxea ~]$ rpm -ql docker-distribution /etc/docker-distribution/registry/config.yml 配置文件 /usr/bin/registry /usr/lib/systemd/system/docker-distribution.service /usr/share/doc/docker-distribution-2.6.2 /usr/share/doc/docker-distribution-2.6.2/AUTHORS /usr/share/doc/docker-distribution-2.6.2/CONTRIBUTING.md /usr/share/doc/docker-distribution-2.6.2/LICENSE /usr/share/doc/docker-distribution-2.6.2/MAINTAINERS /usr/share/doc/docker-distribution-2.6.2/README.md /var/lib/registry 仓库默认目录而后我修改了仓库目录[root@www-linuxea ~]$ mkdir /data/Registry[root@www-linuxea ~]$ cat /etc/docker-distribution/registry/config.yml version: 0.1 log: fields: service: registry storage: cache: layerinfo: inmemory filesystem: rootdirectory: /data/Registry http: addr: :5000[root@www-linuxea ~]$ systemctl start docker-distribution.service [root@www-linuxea ~]$ ss -tlnp|grep 5000 LISTEN 0 32768 *:5000 *:* users:(("registry",pid=9228,fd=3))如果5000端口正常就说明启动成功管理标签我修改了hosts,通过域名来进行打标[root@www-linuxea ~]$ echo "10.10.240.145 registry.linuxea.com" >> /etc/hosts[root@www-linuxea ~]$ cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 10.10.10.250 mirrors.ds.com 10.10.240.145 registry.linuxea.com而后重新打标签,将marksugar/httpd:v7 修改为registry.linuxea.com:5000/marksugar/httpd:v7[root@www-linuxea ~]$ docker tag marksugar/httpd:v7 registry.linuxea.com:5000/marksugar/httpd:v7推送默认是要使用https协议,而服务器断是http,所以这里会报错如下[root@www-linuxea ~]$ docker push registry.linuxea.com:5000/marksugar/httpd:v7 The push refers to repository [registry.linuxea.com:5000/marksugar/httpd] Get https://registry.linuxea.com:5000/v2/: http: server gave HTTP response to HTTPS client通过标记http来解决[root@www-linuxea ~]$ cat /etc/docker/daemon.json { "insecure-registries": ["registry.linuxea.com:5000"] }而后重启[root@www-linuxea ~]$ systemctl restart docker 而后再次推送[root@www-linuxea ~]$ docker push registry.linuxea.com:5000/marksugar/httpd:v7 The push refers to repository [registry.linuxea.com:5000/marksugar/httpd] e37e4dcca4e6: Pushed 7e0e76680fcf: Pushed 7e36f706b93d: Pushed 2d1436269532: Pushed 7030e9e24693: Pushed df64d3292fd6: Pushed v7: digest: sha256:9fd332615f424252c54583f31946816039a5f69d648a35034426be904c75a5e6 size: 1568推送的文件存放在存储目录下,我这里的路径位置是/data/Registry/docker/registry/v2/repositories/marksugar/httpd,在此之下是层目录和上传目录,这些文件又会链接到blobs下[root@DS-linuxea ~]$ ls /data/Registry/docker/registry/v2/repositories/marksugar/httpd _layers _manifests _uploads这些推送过的镜像如果要被pull使用,那么使用的客户端就也需要配置insecure-registriesHarborHarbor是vmware开源的镜像仓库,harbor的安装是非常麻烦的,不过可以使用compose来组合安装。而docker-compose也是一个简单的编排工具,这个编排工具中可以将docker run的命令组合在一个文件中调用,并且可以控制容器的启动顺序。docker-compose的前身是Fig,也是最早最火的编排工具,比k8s早,而后docker公司收购Fig。而在docker-compose中也有多个版本,有2,3版本我们下载离线包安装https://storage.googleapis.com/harbor-releases/release-1.6.0/harbor-offline-installer-v1.6.2.tgz[root@www-Node61_linuxea ~]$ tar xf harbor-offline-installer-v1.6.2.tgz -C /data [root@www-Node61_linuxea ~]$ cd /data/harbor/在harbor.cfg中需要按需修改一些配置,比如hostname,而后./install.sh 在这个docker-compose中定义的文件的映射关系,启动的服务顺序,网络模式,暴露端口等都被事先预设好了,也就是精心设计过的。暂停服务:docker-compose stop重启服务:docker-compose restart启动服务:docker-compose -f ./docker-compose.yaml up -d关闭删除服务:docker-compose down[root@www-Node61_linuxea /data/harbor]# ./install.sh ... [Step 4]: starting Harbor ... Creating network "harbor_harbor" with the default driver Creating harbor-log ... done Creating harbor-adminserver ... done Creating registry ... done Creating redis ... done Creating harbor-db ... done Creating harbor-ui ... done Creating harbor-jobservice ... done Creating nginx ... done ✔ ----Harbor has been installed and started successfully.---- Now you should be able to visit the admin portal at https://registry.linuxea.com. For more details, please visit https://github.com/goharbor/harbor . ...Harbor是监听在宿主机的80端口,我们通过浏览器直接访问。用户名:admin,密码:Harbor12345vmware Harbor的开发有一大部分是中国人,大概也就是如此才会这么快就有中文支持而后可以创建普通用户普通用户也是可以创建项目,推送镜像的客户端推送镜像到仓库新建一个dev项目,而后推送,格式如下推送前需要重新修改标签推送镜像 在项目中标记镜像: docker tag SOURCE_IMAGE[:TAG] registry.linuxea.com/dev/IMAGE[:TAG] 推送镜像到当前项目: docker push registry.linuxea.com/dev/IMAGE[:TAG]NODT那么,在推送之前,我们还需要将此前的配置修改,此前使用distribution,是5000端口,此刻使用Harbor的80端口[root@www-LinuxEA ~]$ cat /etc/docker/daemon.json { "insecure-registries": ["registry.linuxea.com"] }重启[root@www-LinuxEA /data/harbor]$ systemctl restart docker打标签[root@www-LinuxEA ~]$ docker tag marksugar/httpd:v7 registry.linuxea.com/dev/httpd:v7而后登陆到Harbor[root@www-LinuxEA ~]$ docker login registry.linuxea.com Username: linuxea Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded推送即可[root@www-LinuxEA ~]$ docker push registry.linuxea.com/dev/httpd:v7 The push refers to repository [registry.linuxea.com/dev/httpd] e37e4dcca4e6: Pushed 7e0e76680fcf: Pushed 7e36f706b93d: Pushed 2d1436269532: Pushed 7030e9e24693: Pushed df64d3292fd6: Pushed v7: digest: sha256:9fd332615f424252c54583f31946816039a5f69d648a35034426be904c75a5e6 size: 1568回到Harbor,已经能够看到这些详细的信息。
2019年01月21日
3,409 阅读
0 评论
0 点赞
2019-01-18
linuxea:白话容器之CPU与内存资源限制测试(25)
配置在前面了解了容器之CPU与内存资源限制概述,我们进行简单的资源限制测试我们下载lorel/docker-stress-ng测试我们在dockerhub上选择latest版本拉取到本地[root@linuxEA-145 /data/harbor]$ docker pull lorel/docker-stress-ng Using default tag: latest latest: Pulling from lorel/docker-stress-ng c52e3ed763ff: Pull complete a3ed95caeb02: Pull complete 7f831269c70e: Pull complete Digest: sha256:c8776b750869e274b340f8e8eb9a7d8fb2472edd5b25ff5b7d55728bca681322 Status: Downloaded newer image for lorel/docker-stress-ng:latestmemory可以使用 docker run --name stress --rm lorel/docker-stress-ng --help查看帮助 -m N, --vm N start N workers spinning on anonymous mmap (-m N,- vm N启动N个工作人员在匿名mmap上旋转) --vm-bytes N allocate N bytes per vm worker (default 256MB) (--vm-bytes N为每个vm worker分配N个字节(默认为256MB) )我们先对内存进行压测使用-m 指定配置大小为256m,而后使用 --vm 2 ,一个vm的默认是256M,压测观测下[root@linuxEA-145 /data/harbor]$ docker run --name stress --rm -m 256m lorel/docker-stress-ng --vm 2 stress-ng: info: [1] defaulting to a 86400 second run per stressor stress-ng: info: [1] dispatching hogs: 2 vm观测内存的使用情况[root@linuxEA-145 ~]$ docker top stress UID PID PPID C STIME TTY TIME CMD root 12685 12670 0 11:52 ? 00:00:00 /usr/bin/stress-ng --vm 2 root 12716 12685 0 11:52 ? 00:00:00 /usr/bin/stress-ng --vm 2 root 12717 12685 0 11:52 ? 00:00:00 /usr/bin/stress-ng --vm 2 root 12799 12717 70 11:52 ? 00:00:00 /usr/bin/stress-ng --vm 2 root 12810 12716 5 11:52 ? 00:00:00 /usr/bin/stress-ng --vm 2可以使用docker stats stress,内存最多使用在限制内的大小[root@linuxEA-145 ~]$ docker stats stress CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 3b96828e471a stress 0.00% 255.9MiB / 256MiB 99.95% 712B / 42B 2.36GB / 20.5GB 5 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 3b96828e471a stress 137.67% 255.8MiB / 256MiB 99.92% 712B / 42B 2.53GB / 21.8GB 5 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 3b96828e471a stress 137.67% 255.8MiB / 256MiB 99.92% 712B / 42B 2.53GB / 21.8GB 5 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 3b96828e471a stress 139.01% 255.8MiB / 256MiB 99.91% 712B / 42B 2.69GB / 23GB 5可以看到这个内存一直在使用达99%cpu我们在验证下CPU限制使用2核心,也就是最多使用200%,运行8个进程使用(无论起多少进程,只有2核心分配)请注意,这样的限制只能使用2个cpu,那就意味着0-3的cpu任何两个都会被使用,并不固定在那一颗CPU[root@linuxEA-145 /data/harbor]$ docker run --name stress --rm --cpus 2 lorel/docker-stress-ng --cpu 8 stress-ng: info: [1] defaulting to a 86400 second run per stressor stress-ng: info: [1] dispatching hogs: 8 cpu使用docker top stress观测,8个进程已经运行[root@linuxEA-145 ~]$ docker top stress UID PID PPID C STIME TTY TIME CMD root 32201 32185 0 14:19 ? 00:00:00 /usr/bin/stress-ng --cpu 8 root 32232 32201 25 14:19 ? 00:00:01 /usr/bin/stress-ng --cpu 8 root 32233 32201 25 14:19 ? 00:00:01 /usr/bin/stress-ng --cpu 8 root 32234 32201 25 14:19 ? 00:00:01 /usr/bin/stress-ng --cpu 8 root 32235 32201 25 14:19 ? 00:00:01 /usr/bin/stress-ng --cpu 8 root 32236 32201 25 14:19 ? 00:00:01 /usr/bin/stress-ng --cpu 8 root 32237 32201 25 14:19 ? 00:00:01 /usr/bin/stress-ng --cpu 8 root 32238 32201 25 14:19 ? 00:00:01 /usr/bin/stress-ng --cpu 8 root 32239 32201 25 14:19 ? 00:00:01 /usr/bin/stress-ng --cpu 8而CPU最多使用200[root@linuxEA-145 ~]$ docker stats stress CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS d4b2a1641d67 stress 200.05% 18.77MiB / 3.848GiB 0.48% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS d4b2a1641d67 stress 200.05% 18.77MiB / 3.848GiB 0.48% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS d4b2a1641d67 stress 199.37% 18.77MiB / 3.848GiB 0.48% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS d4b2a1641d67 stress 199.37% 18.77MiB / 3.848GiB 0.48% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS d4b2a1641d67 stress 200.50% 18.77MiB / 3.848GiB 0.48% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS d4b2a1641d67 stress 200.50% 18.77MiB / 3.848GiB 0.48% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS d4b2a1641d67 stress 200.10% 18.77MiB / 3.848GiB 0.48% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS假如我们没有限制,将会跑近400%,也就是全部资源被使用当然,也可以指定运行在那一颗之上。比如,限制运行在0,2上这样--cpuset-cpus 0,2 只会运行在0,2不会运行在其他的CPU核心上。[root@linuxEA-145 /data/harbor]$ docker run --name stress --rm --cpuset-cpus 0,2 lorel/docker-stress-ng --cpu 8 stress-ng: info: [1] defaulting to a 86400 second run per stressor stress-ng: info: [1] dispatching hogs: 8 cpu仍然在限制内[root@linuxEA-145 ~]$ docker stats stress CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 21537336658b stress 200.76% 21.71MiB / 3.848GiB 0.55% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 21537336658b stress 200.76% 21.71MiB / 3.848GiB 0.55% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 21537336658b stress 200.29% 21.71MiB / 3.848GiB 0.55% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 21537336658b stress 200.29% 21.71MiB / 3.848GiB 0.55% 0B / 42B 0B / 0B 9 而后我们在宿主机查看top,0,2cpu已经跑满,说明限制是ok的[root@linuxEA-145 /data/harbor]$ top top - 14:25:02 up 85 days, 23:51, 4 users, load average: 2.37, 3.31, 3.04 Tasks: 167 total, 9 running, 91 sleeping, 0 stopped, 0 zombie %Cpu0 : 99.3/0.3 100[||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ] %Cpu1 : 0.7/0.7 1[|| ] %Cpu2 : 100.0/0.0 100[||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||] %Cpu3 : 1.0/1.0 2[|| ] KiB Mem : 29.4/4034596 [||||||||||||||||||||||||||||| ] KiB Swap: 1.9/4190204 [|| ] PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 582 root 20 0 6924 2444 620 R 25.2 0.1 0:04.17 stress-ng-cpu 590 root 20 0 6924 2444 620 R 25.2 0.1 0:04.16 stress-ng-cpu 583 root 20 0 6924 3960 620 R 24.9 0.1 0:04.16 stress-ng-cpu 584 root 20 0 6924 3960 620 R 24.9 0.1 0:04.16 stress-ng-cpu 585 root 20 0 6924 2444 620 R 24.9 0.1 0:04.16 stress-ng-cpu 587 root 20 0 6924 2444 620 R 24.9 0.1 0:04.16 stress-ng-cpu --cpu-shares共享那如果是共享的方式就不同了共享的方式--cpu-shares,在没有使用的时候都会被吃掉,如果有其他的容器运行则分配给别人[root@linuxEA-145 /data/harbor]$ docker run --name stress --rm --cpu-shares 1024 lorel/docker-stress-ng stress --cpu 8 stress-ng: info: [1] defaulting to a 86400 second run per stressor stress-ng: info: [1] dispatching hogs: 8 cpu只运行一个容器的时候,CPU 400%[root@linuxEA-145 ~]$ docker stats stress CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS dc3c61506fb9 stress 399.67% 17.14MiB / 3.848GiB 0.44% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS dc3c61506fb9 stress 399.67% 17.14MiB / 3.848GiB 0.44% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS dc3c61506fb9 stress 400.42% 17.14MiB / 3.848GiB 0.44% 0B / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS dc3c61506fb9 stress 400.42% 17.14MiB / 3.848GiB 0.44% 0B / 42B 0B / 0B 9我们在运行一个容器,也做限制为512[root@linuxEA-145 /data/harbor]$ docker run --name stress1 --rm --cpu-shares 512 lorel/docker-stress-ng stress --cpu 8 stress-ng: info: [1] defaulting to a 86400 second run per stressor stress-ng: info: [1] dispatching hogs: 8 cpu在来观测此前运行一个容器时候的stress,现在已经掉到266%左右[root@linuxEA-145 ~]$ docker stats stress CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS dc3c61506fb9 stress 265.84% 17.14MiB / 3.848GiB 0.44% 1.07kB / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS dc3c61506fb9 stress 267.23% 17.14MiB / 3.848GiB 0.44% 1.07kB / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS dc3c61506fb9 stress 267.23% 17.14MiB / 3.848GiB 0.44% 1.07kB / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS dc3c61506fb9 stress 265.52% 17.14MiB / 3.848GiB 0.44% 1.07kB / 42B 0B / 0B 而stress1的使用是133%[root@linuxEA-145 ~]$ docker stats stress1 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 2db9d935886c stress1 133.23% 17.16MiB / 3.848GiB 0.44% 1.07kB / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 2db9d935886c stress1 132.16% 17.16MiB / 3.848GiB 0.44% 1.07kB / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 2db9d935886c stress1 132.16% 17.16MiB / 3.848GiB 0.44% 1.07kB / 42B 0B / 0B 9 CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 2db9d935886c stress1 133.08% 17.16MiB / 3.848GiB 0.44% 1.07kB / 42B 0B / 0B CPU资源被两个容器动态瓜分在资源紧张的情况下,可以调整--oom-kill-disadble禁用被kill,和--oom-score-adj调整优先级来尽量避免优先被kill
2019年01月18日
3,527 阅读
0 评论
0 点赞
2019-01-17
linuxea:白话容器之CPU与内存资源限制概述(24)
我们知道容器能够运行,依赖内核的两个特性,一个是名称空间,一个是控制组。默认在docker中是没有任何资源限制的,在某些极端情况下能够几乎耗尽docker主机之上的所有资源。在此基础之上docker provides提供了一个控制容器能够使用多少内存,cpu,io,我们可以进行控制cpu和内存,而IO较弱控制。而其中的内存是非可压缩资源,CPU是可压缩资源。当容器内的进程耗尽CPU时,并且申请更多内存时候,可能会产生OOM。而CPU则不会出现这种问题。这些资源的限制依赖于capabilities资源限制从名称空间和cgroup来进行定义MemoryOOM如果在linux主机上,内核探测到当前宿主机已经没有足够内存可用于执行某些重要的系统功能,就会抛出OOME,并且开始启动kill 进程,以便于释放资源。一旦发生OOME,任何进程都有可能会被杀死 ,包括docker daemon在内如果内核发现内存被几乎耗尽无法执行本身的运作的时候,会进行检测使用内存异常的hogs进程。但是并不是使用内存最多的就是被杀掉的进程。这可能取决于,申请的内存总大小内耗尽比例来取决最佳被杀掉的进程,这个列表顺序可能是逆序的。为此,docker特地调整了docker daemon的OOM优先级,但是容器的优先级并未调整。为了便于控制,引入了一个oom-adj的功能,以防止系统中的重要进程被杀死,并定义要杀死的进程的顺序。oom_adj的可能值范围为-17到+15。分数越高,相关过程越有可能被OOM杀手杀死。如果 oom_adj设置为-17,则不会考虑将该进程用于OOM查杀。在每一个进程可以分配一个OOM-score的得分计算,根据其不良分数选择在内存不足情况下被杀死,,这个得分计算根据内存的申请的空间参考:https://lwn.net/Articles/317814/ https://lwn.net/Articles/391222/ https://lwn.net/Articles/548180/ https://lwn.net/Articles/391206/对于一些非常重要的容器,在启动的时候就需要调整oom_adj,另外也可以定义容器的策略,在出现OOM被kill后就restart默认是没有对资源限制的,限制容器的内存和CPU资源是有选项可以使用:内存资源raw,swap| `-m` 要么 `--memory=` | 限制容器使用内存,单位是k,b,m,g作为单位使用,可单独使用 | | `--memory-swap`* | 允许此容器交换到磁盘的内存量。查看[`--memory-swap`详情](https://docs.docker.com/config/containers/resource_constraints/#--memory-swap-details)。这个选项生效依赖于raw的选项是否配置 | | `--memory-swappiness` | 默认情况下,主机内核可以交换容器使用的匿名页面的百分比。您可以设置`--memory-swappiness`0到100之间的值,以调整此百分比。查看[`--memory-swappiness`详情](https://docs.docker.com/config/containers/resource_constraints/#--memory-swappiness-details)。 0并不是不使用| | `--memory-reservation` | 允许您指定小于软件限制的软限制`--memory`,当Docker检测到主机上的争用或内存不足时,该限制将被激活。如果使用`--memory-reservation`,则必须将其设置为低于`--memory`优先级。因为它是软限制,所以不保证容器不超过限制。 | | `--kernel-memory` | 容器可以使用的最大内核内存量。允许的最小值是`4m`。由于内核内存无法换出,因此内核内存不足的容器可能会阻塞主机资源,这可能会对主机和其他容器产生副作用。查看[`--kernel-memory`详情](https://docs.docker.com/config/containers/resource_constraints/#--kernel-memory-details)。 | | `--oom-kill-disable` | 默认情况下,如果发生内存不足(OOM)错误,内核会终止容器中的进程。要更改此行为,请使用该`--oom-kill-disable`选项。仅在已设置`-m/--memory`选项的容器上禁用OOM杀手。如果`-m`未设置该标志,则主机可能会耗尽内存,并且内核可能需要终止主机系统的进程才能释放内存。 |参考:https://docs.docker.com/config/containers/resource_constraints/#limit-a-containers-access-to-memory--memory-swap和memory联系与区别memswapmemory功能正数s正数M容器可用中总空间为s,其中ram为M,swap为(s-m),若S=M,则无可用swap资源。这里的可用内存并不是s+m!0正数M下相当于未设置swap不设置正数M若主机(docker host)启用了swap,则容器的可用swap为2*M-1正数M若主机(docker host)启用了swap,则容器可使用最大至宿主机上的所有swap空间的swap资源容器内使用free命令看到的swap空间并不具有其所展现出的空间的指示意义CPU每一个容器都可以使用宿主机上所有的CPU资源。作为用户来讲,可以设置各种约束来限制给定容器访问主机的CPU额度。我们知道,CPU的核心数是少于进程数的,一个系统之上运行了很多个进程,运行的进程数量大于核心数量的时候, 那个才是优先被运行?大多数用户使用和配置是由CFS调度程序来决定的。内核管理中最重要的一个组件CFS(Completely Fair Scheduler),处理调度进程在本地的核心之上,用于普通Linux进程的Linux内核CPU调度程序。多个运行时标志允许您配置容器具有的CPU资源访问量。使用这些设置时,Docker会修改主机上容器的cgroup的设置。然而每个进程都是有优先级的,这种非实时优先级,有效范围是100-139,这个范围是可以使用nice(niceness scale)进行调整,-20到19,数字越小优先级越高。默认nice值为零。在1.13及更高版本中,支持实时调度程序。另外,还有实时优先级,0-99,默认范围为1到99,这些都是内核级的。然后100到139用于用户空间(非实时),调度器CFS就是调度这些100-139之间的进程的延伸阅读:CFS: https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txtCFS: https://en.wikipedia.org/wiki/Completely_Fair_Scheduler进程调度:https://en.wikipedia.org/wiki/Completely_Fair_SchedulerCPU调度:https://www.studytonight.com/operating-system/cpu-scheduling进程优先级调整:https://bencane.com/2013/09/09/setting-process-cpu-priority-with-nice-and-renice/https://developer.ibm.com/tutorials/l-lpic1-103-6/https://www.ostechnix.com/change-priority-process-linux/https://www.nixtutor.com/linux/changing-priority-on-linux-processes/https://www.tecmint.com/set-linux-process-priority-using-nice-and-renice-commands/CPU资源也分为io密集型和CPU密集型,对于cpu密集型的可能需要调低优先级,当调度后就会耗时较长,而IO密集型是IO调度。对于占用很长时间的进程动态调低优先级,对于那些占用CPU很少又经常调度不上去的(CPU)将会调整高一些。CPU分配:选项描述--cpus=<value>指定容器可以使用的可用CPU资源量。例如,如果主机有两个CPU并且您已设置--cpus="1.5",则容器最多保证一个半CPU。这相当于设置--cpu-period="100000"和--cpu-quota="150000"。可在Docker 1.13及更高版本中使用。--cpu-period=<value>指定CPU CFS调度程序周期,它与并用 --cpu-quota。默认为100微秒。大多数用户不会更改默认设置。如果您使用Docker 1.13或更高版本,请--cpus改用。--cpu-quota=<value>对容器施加CPU CFS配额。--cpu-period限制前容器限制为每秒的微秒数。作为有效上限。如果您使用Docker 1.13或更高版本,请--cpus改用。--cpuset-cpus限制容器可以使用的特定CPU或核心。如果您有多个CPU,则容器可以使用的以逗号分隔的列表或连字符分隔的CPU范围。第一个CPU编号为0.有效值可能是0-3(使用第一个,第二个,第三个和第四个CPU)或1,3(使用第二个和第四个CPU)。--cpu-shares将此标志设置为大于或小于默认值1024的值,以增加或减少容器的重量,并使其可以访问主机的CPU周期的较大或较小比例。仅在CPU周期受限时才会强制执行此操作。当有足够的CPU周期时,所有容器都会根据需要使用尽可能多的CPU。这样,这是一个软限制。--cpu-shares不会阻止容器以群集模式进行调度。它为可用的CPU周期优先考虑容器CPU资源。它不保证或保留任何特定的CPU访问权限。参考:https://docs.docker.com/config/containers/resource_constraints/#configure-the-default-cfs-scheduler而--cpu-shares是按照比例切分。1024:512比如当前系统上运行了两个人容器,第一个容器是1024,第二个容器是512,假如这俩个容器都需要可能多的使用CPU。假如CPU资源有100份(100%),分为2分之一,各占512,而CPU资源以512为单位分为三份在两个容器上,如下:第一个容器占2份,而第二个容器占用1份,如果此时第二个容器启动后并没有占用CPU,那么第一个容器就可以占用第二个容器的512,这种方式就是共享式。在需要的时候就分配需要的额度,不需要的时候就给需要的使用。1024:512:2048假如现在有更大的比例,如下图这样一来就是分为了七份,2+1+4,分七份后后可用资源占用比例就不一样了,最后的2048是分成了4份542。同样,如果其中某一份容器或多个容器暂时不占用分配自己的CPU资源,仍然会被其他繁忙的容器所占用全部。也就是说,只要容器都在使用,就按照比例分配,如果只有一个使用,其他的不使用,这个使用的容器能够占用所有的CPU资源。如果有两个在使用,就按照剩下的比例分配给使用的,这个过程是随时动态调整的。任何一个容器不使用,就会被其他使用的容器说分配掉。CPU是可压缩资源,可随时加入更多的容器使用,只不过不同的分法,得到的结果不一样而已。CPU可压缩资源通过共享方式来分派,可压缩,也可随时调整比例。CPUshares有一特点,假如有4核心cpu,其中没一个容器的进程可任意调度到任何一个核心上面运行。一共使用1024比例,但是另外2个容器都不运行,那这个容器就不单单有一颗CPU的运算能力,而是有4颗CPU的运算能力,一颗CPU是100%,4个就相当于有400%的CPU。--cpus当然,也可以限制,假设如果一共有4核心,一个进程最多使用2个核心,且无论其他CPU空闲超过2个以上或者其他,被限制的cpu只能使用2核心,另外两个核心是空闲的(任意取其二,剩下不取) 。如下图左假设使用限制是2核心,也就是说,在4核心的cpu上使用的最多只能是200%,一个核心为100%,那也就是2颗核心。而现在可能是另外的一种方式,同样适用2核心,最多使用200%,但是却是每个核心各50%,重量不超过200%即可。如下图右但是,我们也可以限制核心数。--cpuset-cpus--cpus意味着这个进程只能运行在那个CPU核心。假如有4个核心,用的是0和3进行编号,那1和2就不能使用这些分配可以分为几种:1,按照压缩方式比例分配2,限定最多使用的核心数3,限定使用那些个CPU假如只有--cpuset-cpus限制了只能使用的0和1,那说明只能使用两个CPU,也就是200%,也可以限制使用的cpu时间周期和配额,这些选项在run或create时间使用。
2019年01月17日
4,040 阅读
0 评论
0 点赞
2019-01-16
linuxea:白话容器之dockerfile ARG和ONBUILD使用(6)(23)
shell该SHELL指令允许覆盖用于shell形式的命令的默认shell 。Linux上的默认shell是["/bin/sh", "-c"],而在Windows上["cmd", "/S", "/C"]。该SHELL指令必须以JSON格式写入Dockerfile。参考:https://docs.docker.com/engine/reference/builder/#shellSTOPSIGNAL该STOPSIGNAL指令设置将发送到容器的系统调用信号以退出。此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如9,或SIGNAME格式的信号名,例如SIGKILL,例如15,停止容器。如果要发送其他的信号就要在这里定义STOPSIGNAL signalARGARG指令定义了一个变量,可以docker build使用该--build-arg <varname>=<value> 标志在构建时将该变量传递给构建器。这样定义的Dockerfile可以适用于较多的场景,尤其是程序版本迭代。如果指定了未在Dockerfile中定义的构建参数,则构建会输出警告。示例:定义ARG author默认是"linuxea.com.cn"ARG author="linuxea.com.cn" LABEL maintainer="${author}"[root@linuxEA-145 /data/linuxea3]$ cat Dockerfile FROM nginx:1.14.2-alpine ARG author="linuxea.com.cn" LABEL maintainer="${author}" ENV NGINX_ROOT="/data/wwwroot" ADD entrypoint.sh /bin/entrypoint.sh ADD index.html ${NGINX_ROOT}/ EXPOSE 8080/tcp 80/tcp HEALTHCHECK --interval=3s --timeout=3s --start-period=3s CMD wget -O - -q https://${IP:-0.0.0.0}:${NGPORT:-80}||exit 1 #HEALTHCHECK --start-period=3s CMD wget -O - -q https://${IP:-0.0.0.0}:${NGPORT} || exit 1 CMD ["/usr/sbin/nginx","-g","daemon off;"] ENTRYPOINT ["/bin/entrypoint.sh"]build[root@linuxEA-145 /data/linuxea3]$ docker build --build-arg author="mark www.linuxea.com" -t marksugar/nginx:v5 .查看,marksugar/nginx:v5的Labels是默认的linuxea.com.cn[root@linuxEA-145 /data/linuxea3]$ docker inspect -f {{.ContainerConfig.Labels}} marksugar/nginx:v5 map[maintainer:linuxea.com.cn]而后重新build,重新赋值--build-arg author="mark www.linuxea.com"[root@linuxEA-145 /data/linuxea3]$ docker build --build-arg author="mark www.linuxea.com" -t marksugar/nginx:v6 .而后在查看,赋值被生效[root@linuxEA-145 /data/linuxea3]$ docker inspect -f {{.ContainerConfig.Labels}} marksugar/nginx:v6 map[maintainer:mark www.linuxea.com]ONBUILDdocker onbuild用于指定当前的docker镜象用作另一个镜象的基本镜象时候运行的命令,在使用前,需要一个静态的基本镜象,而后其动态配置会在新的镜象(子镜象)发生作用,或者在新镜象依赖之前构建镜象的情况下使用!ONBUILD用于在Dockerfile中定义一个触发器,Dockerfile用于build镜像文件,此镜像文件可作为base image被另一个Dockerfile用作FROM指令的参数,并以之构建新的映像文件疑问当使用各种指令创建一个dockerfile,并在dockerfile指定了onbuild指令,当我们使用docker build使用当前的dockerfile构建镜象的时候,将会创建一个新的docker镜象,但onbuild指令不会应用于当前的docker镜象,仅仅作为将要创建新的景象用作为另外一个dockerfile中的基本镜象时候,才会应用此选项。在后面的这个Dockerfile中的FROM指令在build过程中被执行时,将会“触发”创建其base image的Dockerfile文件中的ONBUILD指令定义的触发器ONBULD <INSTRUCTION>尽管任何指令都可注册成为触发器指令,但ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,例如:mysql:5.6-onbuild在ONBUILD指令中使用ADD或COPY指令如果缺少指定的源文件时会失败(比如二次build copy,本地却无文件)。多数情况下,ONBUILD会执行ADD或者RUN进行下载安装等。也就说ONBUILD不会在自己构建的时候执行,而是在被其他人使用作为基础镜像的时候才会执行。添加一条ONBUILD,示例如下:ONBUILD ADD https://10.10.240.145/CentOS-Base.repo /etc/如下:[root@linuxEA-145 /data/linuxea3]$ cat Dockerfile FROM nginx:1.14.2-alpine ARG author="linuxea.com.cn" LABEL maintainer="${author}" ENV NGINX_ROOT="/data/wwwroot" ADD entrypoint.sh /bin/entrypoint.sh ADD index.html ${NGINX_ROOT}/ EXPOSE 8080/tcp 80/tcp HEALTHCHECK --interval=3s --timeout=3s --start-period=3s CMD wget -O - -q https://${IP:-0.0.0.0}:${NGPORT:-80}||exit 1 #HEALTHCHECK --start-period=3s CMD wget -O - -q https://${IP:-0.0.0.0}:${NGPORT} || exit 1 ONBUILD ADD https://10.10.240.145/CentOS-Base.repo /etc/ CMD ["/usr/sbin/nginx","-g","daemon off;"] ENTRYPOINT ["/bin/entrypoint.sh"]而后build为marksugar/httpd:v7[root@linuxEA-145 /data/linuxea3]$ docker build -t marksugar/httpd:v7 . Sending build context to Docker daemon 4.608kB Step 1/11 : FROM nginx:1.14.2-alpine ---> d956af1ad36a Step 2/11 : ARG author="linuxea.com.cn" ---> Using cache ---> c4c543206ad1 Step 3/11 : LABEL maintainer="${author}" ---> Using cache ---> 36edfcb86dfb Step 4/11 : ENV NGINX_ROOT="/data/wwwroot" ---> Using cache ---> 6547ed95f45a Step 5/11 : ADD entrypoint.sh /bin/entrypoint.sh ---> Using cache ---> d650f4dcb46c Step 6/11 : ADD index.html ${NGINX_ROOT}/ ---> Using cache ---> 865b4df58910 Step 7/11 : EXPOSE 8080/tcp 80/tcp ---> Using cache ---> 1454ea1fc5e3 Step 8/11 : HEALTHCHECK --interval=3s --timeout=3s --start-period=3s CMD wget -O - -q https://${IP:-0.0.0.0}:${NGPORT:-80}||exit 1 ---> Using cache ---> 157834157357 Step 9/11 : ONBUILD ADD https://10.10.240.145/CentOS-Base.repo /etc/ ---> Running in 37e29f61d449 Removing intermediate container 37e29f61d449 ---> f334451b2c4c Step 10/11 : CMD ["/usr/sbin/nginx","-g","daemon off;"] ---> Running in d3b24f896853 Removing intermediate container d3b24f896853 ---> b9307347b1ce Step 11/11 : ENTRYPOINT ["/bin/entrypoint.sh"] ---> Running in cd1f126e961f Removing intermediate container cd1f126e961f ---> a79987f1e18a Successfully built a79987f1e18a Successfully tagged marksugar/httpd:v7[root@linuxEA-145 /data/linuxea3]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE marksugar/httpd v7 a79987f1e18a About a minute ago 17.7MB重新写一个Dockerfile,调用刚刚构建的marksugar/httpd:v7[root@linuxEA-145 /data/linuxea4]$ cat Dockerfile FROM marksugar/httpd:v7 RUN echo "helo" >> /tmp/linuxea.txt在build的时候,就会执行上一个Dockerfile中的ONBUILD命令,如下:[root@linuxEA-145 /data/linuxea4]$ docker build -t onbuild:1 . Sending build context to Docker daemon 2.048kB Step 1/2 : FROM marksugar/httpd:v7 # Executing 1 build trigger Downloading [==================================================>] 1.664kB/1.664kB ---> b64f3cd2ba7f Step 2/2 : RUN echo "helo" >> /tmp/linuxea.txt ---> Running in e9f45b68bb24 Removing intermediate container e9f45b68bb24 ---> 63bced5b493c Successfully built 63bced5b493c Successfully tagged onbuild:1而后run起来验证下[root@linuxEA-145 /data/linuxea4]$ docker run --name onbuild --rm onbuild:1 ls /etc/CentOS-Base.repo /etc/CentOS-Base.repo[root@linuxEA-145 /data/linuxea4]$ docker run --name onbuild --rm onbuild:1 cat /etc/CentOS-Base.repo # CentOS-Base.repo # # The mirror system uses the connecting IP address of the client and the # update status of each mirror to pick mirrors that are updated to and # geographically close to the client. You should use this for CentOS updates # unless you are manually picking other mirrors. # # If the mirrorlist= does not work for you, as a fall back you can try the # remarked out baseurl= line instead. # # [base] name=CentOS-$releasever - Base mirrorlist=https://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra #baseurl=https://mirror.centos.org/centos/$releasever/os/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 ...
2019年01月16日
4,024 阅读
0 评论
0 点赞
2019-01-14
linuxea:白话容器之dockerfile health check使用(5)(22)
health check当我们基于镜像启动一个容器的时候,容器在什么时候退出,又在什么时候运行?事实上只要这个容器的主进程不是运行在后台,也没有停止,那么这个容器就不会停止。容器在判断容器正常与否,并不会根据容器是否能够正常服务,而仅仅是看容器主进程是否运行着,因此这种判断机制并不能说明容器就是健康的。那么我们就可以使用curl,或者wget,向主页发起请求,如果主页内容状态是对的,或者内容是我们期望的来判断是否运行正常,这样的精度才是我们想要的health check并不是检测一次就是ok的,他是一个周期的持续性的检测当容器指定了运行状况检查时,除了正常状态外,它还具有运行状况。这个状态最初是starting。每当健康检查通过时,它就会变成healthy(以前的状态)。经过一定数量的连续失败后,它就变成了unhealthy--interval=DURATION(间隔时间,默认值:30s)--timeout=DURATION(超时秒数,默认值:30s)--start-period=DURATION(默认值:0s)--retries=N(失败的重试次数,默认值:3)start period:容器在启动的时候,可能需要一定的准备的初始化时间,如果容器被run就开始检测,那如果容器也没有准备妥当,那此时检测肯定是失败的。那么就需要给容器一个启动的准备时间来做初始化。而这个start-period就是。检测发出后返回状态值:0:成功 - 容器健康且随时可用1:不健康 - 容器无法正常工作2:保留 - 不要使用此退出代码例如,要检查每五分钟左右网络服务器能够在三秒钟内为网站的主页面提供服务:HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f https://localhost/ || exit 1这样以来就不依赖进程是否运行来判断,而是判断访问是否正常来判断接着上面的Dockerfile,添加一行,时间均是3s,方便测试:--interval=3s--timeout=3s--start-period=3sHEALTHCHECK --interval=3s --timeout=3s --start-period=3s CMD wget -O - -q https://${IP:-0.0.0.0}:${NGPORT:-80}[root@linuxEA-145 /data/linuxea3]$ cat Dockerfile FROM nginx:1.14.2-alpine LABEL maintainer="linuxea.com" ENV NGINX_ROOT="/data/wwwroot" ADD entrypoint.sh /bin/entrypoint.sh ADD index.html ${NGINX_ROOT}/ EXPOSE 8080/tcp 80/tcp HEALTHCHECK --interval=3s --timeout=3s --start-period=3s CMD wget -O - -q https://${IP:-0.0.0.0}:${NGPORT:-80} || exit 1 #HEALTHCHECK --start-period=3s CMD wget -O - -q https://${IP:-0.0.0.0}:${NGPORT} || exit 1 CMD ["/usr/sbin/nginx","-g","daemon off;"] ENTRYPOINT ["/bin/entrypoint.sh"]而后build[root@linuxEA /data/linuxea3]$ docker build -t marksugar/nginx:v3 .run起来后,就会发起wget -O - -q https://${IP:-0.0.0.0}:${NGPORT:-80},说明状态健康[root@linuxEA-145 /data/linuxea3]$ docker run --name linuxea --rm -e "NGPORT=8080" marksugar/nginx:v3 127.0.0.1 - - [08/Dec/2018:15:23:15 +0000] "GET / HTTP/1.1" 200 28 "-" "Wget" "-" 127.0.0.1 - - [08/Dec/2018:15:23:18 +0000] "GET / HTTP/1.1" 200 28 "-" "Wget" "-" 127.0.0.1 - - [08/Dec/2018:15:23:21 +0000] "GET / HTTP/1.1" 200 28 "-" "Wget" "-" 127.0.0.1 - - [08/Dec/2018:15:23:24 +0000] "GET / HTTP/1.1" 200 28 "-" "Wget" "-" 127.0.0.1 - - [08/Dec/2018:15:23:27 +0000] "GET / HTTP/1.1" 200 28 "-" "Wget" "-" 127.0.0.1 - - [08/Dec/2018:15:23:30 +0000] "GET / HTTP/1.1" 200 28 "-" "Wget" "-" 127.0.0.1 - - [08/Dec/2018:15:23:33 +0000] "GET / HTTP/1.1" 200 28 "-" "Wget" "-" 127.0.0.1 - - [08/Dec/2018:15:23:36 +0000] "GET / HTTP/1.1" 200 28 "-" "Wget" "-"此时我将端口修改为81,而81并没有监听,wget将失败,也就没有了wget日志,而docker ps 将能看到状态为unhealthy,说明不健康[root@linuxEA-145 /data/linuxea3]$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 13fcf1bd14c4 marksugar/nginx:v4 "/bin/entrypoint.sh …" 19 seconds ago Up 18 seconds (unhealthy) 80/tcp, 8080/tcp linuxea查看docker inspect --format "{{json .State.Health }}" <container name> | jq示例2我创建了一个小的node.js web服务器,只需用'OK'响应任何请求。但是,服务器还有一个切换开/关状态的开关,而不会实际关闭服务器的进程。这是它的代码:"use strict"; const http = require('http'); function createServer () { return http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('OK\n'); }).listen(8080); } let server = createServer(); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); if (server) { server.close(); server = null; res.end('Shutting down...\n'); } else { server = createServer(); res.end('Starting up...\n'); } }).listen(8081);当服务器处于开启状态时,它将在端口8080处侦听并返回OK到任何进入该端口的请求。curl 8081端口将关闭服务器,另一个curl将再次启用它:[root@linuxEA-145 ~]$ node server.js # switch to another terminal [root@linuxEA-145 ~]$ curl 127.0.0.1:8080 # OK [root@linuxEA-145 ~]$ curl 127.0.0.1:8081 # Shutting down... [root@linuxEA-145 ~]$ curl 127.0.0.1:8080 # curl: (7) Failed to connect to 127.0.0.1 port 8080: Connection refused [root@linuxEA-145 ~]$ curl 127.0.0.1:8081 # Starting up... [root@linuxEA-145 ~]$ curl 127.0.0.1:8080 # OK现在让我们将server.js放入带有运行状况检查的Dockerfile中,构建一个镜像并将其作为容器启动:FROM node COPY server.js / EXPOSE 8080 8081 HEALTHCHECK --interval=5s --timeout=10s --retries=3 CMD curl -sS 127.0.0.1:8080 || exit 1 CMD [ "node", "/server.js" ][root@linuxEA-145 ~]$ docker build . -t server:latest # Lots, lots of output [root@linuxEA-145 ~]$ docker run -d --rm -p 8080:8080 -p 8081:8081 server # ec36579aa452bf683cb17ee44cbab663d148f327be369821ec1df81b7a0e104b [root@linuxEA-145 ~]$ curl 127.0.0.1:8080 # OK创建的容器ID开头ec3,这应该足以在以后识别它,所以现在我们可以跳转到健康检查监视容器运行状况Docker用于检查容器健康状况的主要命令是 docker inspect。它产生巨大的JSON作为响应,但我们感兴趣的唯一部分是它的 State.Health属性:[root@linuxEA-145 ~]$ docker inspect ec3 | jq '.[].State.Health' #{ # "Status": "healthy", # "FailingStreak": 0, # "Log": [ # { # "Start": "2017-06-27T04:07:03.975506353Z", # "End": "2017-06-27T04:07:04.070844091Z", # "ExitCode": 0, # "Output": "OK\n" # }, #... }当前状态是“健康的”,我们甚至可以看到健康检查记录 Log 收集。但是,在调用端口8081并等待3 * 5秒(允许三次检查失败)之后,镜像将会改变。[root@linuxEA-145 ~]$ curl 127.0.0.1:8081 # Shutting down... # 15 seconds later [root@linuxEA-145 ~]$ docker inspect ec3 | jq '.[].State.Health' #{ # "Status": "unhealthy", # "FailingStreak": 4, # "Log": [ # ... # { # "Start": "2017-06-27T04:16:27.668441692Z", # "End": "2017-06-27T04:16:27.740937964Z", # "ExitCode": 1, # "Output": "curl: (7) Failed to connect to 127.0.0.1 port 8080: Connection refused\n" # } # ] #}等了15秒多一点,所以健康检查连续4次失败(FailingStreak)。正如预期的那样,docker的状态确实变为“不健康”。但是,只要至少一次健康检查成功,Docker就会将容器恢复到“健康”状态:[root@linuxEA-145 ~]$ curl 127.0.0.1:8081 # Starting up... [root@linuxEA-145 ~]$ docker inspect ec3 | jq '.[].State.Health.Status' # "healthy"使用Docker事件检查运行状况除了直接检查容器状态外,我们还可以听取docker events:[root@linuxEA-145 ~]$ docker events --filter event=health_status # 2017-06-27T00:23:03.691677875-04:00 container health_status: healthy ec36579aa452bf683cb17ee44cbab663d148f327be369821ec1df81b7a0e104b (image=server, name=eager_swartz) # 2017-06-27T00:23:23.998693118-04:00 container health_status: unhealthy ec36579aa452bf683cb17ee44cbab663d148f327be369821ec1df81b7a0e104b (image=server, name=eager_swartz)Docker事件可能有点繁琐,这就是我必须使用的原因--filter。命令本身不会立即退出并保持运行,在事件发生时打印出事件。健康状况和Swarm服务为了尝试运行状况检查如何影响Swarm服务,我暂时将本地Docker实例转换为Swarm模式docker swarm init,现在我可以执行以下操作:[root@linuxEA-145 ~]$ docker service create -p 8080:8080 -p8081:8081 \ --name server \ --health-cmd='curl -sS 127.0.0.1:8080' \ --health-retries=3 \ --health-interval=5s \ server #unable to pin image server to digest: errors: #denied: requested access to the resource is denied #unauthorized: authentication required #ohkvwbsk06vkjyx69434ndqij这使用本地构建的server 镜像将新服务放入Swarm中。Docker对镜像是本地的并返回一堆错误这一事实并不满意,但最终确实返回了新创建的服务的ID:docker service ls #ID NAME MODE REPLICAS IMAGE #ohkvwbsk06vk server replicated 1/1 servercurl 127.0.0.1:8080 将再次工作,发送请求8081将像往常一样关闭服务。但是,这次短时间后端口8080将在没有明确启用服务器的情况下再次开始工作。事情是,只要Swarm注意到容器变得不健康,因此整个服务不再满足所需状态(“运行”),它就会完全关闭容器并启动一个新容器。通过检查我们server 服务的任务集合,我们实际上可以看到它的痕迹 :[root@linuxEA-145 ~]$ docker service ps server #ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS #mt67hkhp7ycr server.1 server moby Running Running 50 seconds ago #pj77brhfhsjm \_ server.1 server moby Shutdown Failed about a minute ago "task: non-zero exit (137): do…"每个Swarm容器都有一个分配给它的任务。当容器死亡时,相应的任务也会关闭,Swarm会创建一对新任务和一个容器。docker service ps 显示给定服务和容器的整个任务链死亡和复活。在我们的特定情况下server,id的初始任务pj77brhfhsjm被标记为失败,docker inspect 甚至说明原因:[root@linuxEA-145 ~]$ docker inspect pj77 | jq '.[].Status.Err' # "task: non-zero exit (137): dockerexec: unhealthy container"“unhealthy container”,这就是原因。但最重要的是,整个服务自动从不健康的状态恢复,几乎没有明显的停机时间Docker运行状况检查是一个小功能,允许将shell命令附加到容器并使用它来检查容器的内容是否足够活跃。对于Docker引擎独立模式下的容器,它只是为它添加健康/不健康的属性(health_status当值更改时加上docker事件),但在Swarm模式下,它实际上将关闭有故障的容器并创建一个停机时间非常短的新容器。
2019年01月14日
4,448 阅读
0 评论
0 点赞
2019-01-13
linuxea:白话容器之dockerfile COPY与ADD的最佳实践(4)(21)
COPY与ADD的最佳实践COPY和ADD是可以将文件放入容器中,那么最好的用法是COPY而不是ADD,当然了,除非文件是tar包并且像自动解压此Dockerfile指令将一个或多个本地文件或文件夹复制到Docker镜像中的目标中。COPY <source>... <destination>COPY ["<source>",... "<destination>"] (包含空格的路径)使用COPY的示例Dockerfile这是COPY在Dockerfile中使用Ruby应用程序的方法。FROM ruby:2.5.1 WORKDIR /usr/src/app COPY Gemfile Gemfile.lock ./ RUN bundle install COPY . . CMD ["./your-daemon-or-script.rb"]它积聚在镜象中的层,先从父镜象ruby:2.5.1,使用所定义FROM。Docker指令WORKDIR为其后面的COPY或者ADD 指令定义工作目录使用COPY它时,会将文件从本地源(在本例 .中为当前目录中的文件)复制到定义的位置WORKDIR。在上面的示例中,第二个 .引用镜象中工作目录中的当前目录。使用COPY创建镜象图层的最佳做法Docker建议使用COPY以在不同镜象层中保存不同文件上下文的方式创建镜象层。这意味着重建镜象是有效的。最不可能更改的文件应位于较低层,而最可能更改的文件应最后添加。如果您有多个Dockerfile步骤使用上下文中的不同文件,则COPY它们是单独的,而不是一次性完成。这可确保每个步骤的构建缓存仅在特定所需文件更改时失效(强制重新执行该步骤)。 编写Dockerfiles的最佳实践上面的Dockerfile示例演示了此原则。通过复制Gemfiles,然后RUN bundle install 使用已安装的Ruby Gems创建一个镜象层,可以对其进行缓存。最后两条Docker指令将应用程序的文件复制到镜象中,并使用默认命令设置CMD。这意味着如果您更改任何应用程序的文件,则可以使用缓存的父级和中间层重建Docker镜像。这比从头开始构建所有这些更有效。为什么不应该使用ADD该ADD指令具有类似的语法COPY。除了将本地文件和目录复制到Docker镜像中的目标之外,它还具有一些附加功能。ADD <source>... <destination>ADD ["<source>",... "<destination>"] (包含空格的路径)但是,Docker的Dockerfile最佳实践官方指南指出,这COPY是ADD大多数用途中的首选指令。一般而言,虽然*ADD* and *COPY*在功能上类似,但是*COPY*是优选的。那是因为它更透明*ADD*。*COPY*仅支持将本地文件基本复制到容器中,同时*ADD*具有一些功能(如仅限本地的tar提取和远程URL支持),这些功能并不是很明显。因此,最好的用途*ADD*是将本地tar文件自动提取到镜象中如:编写Dockerfiles的最佳实践*ADD rootfs.tar.xz /*其中一个ADD附加功能是它可以从URL复制文件,但Docker建议不要将其用于此目的。从URL复制文件的最佳做法如果ADDsource是URL,它将下载文件并将其复制到Docker镜像中的目标位置。docker表明,它往往是效率不高,从使用URL复制ADD,这是最好的做法,以使用其他策略,包括所需的远程文件。由于镜象大小很重要,ADD因此强烈建议不要使用从远程URL获取包。你应该使用curl或wget代替。这样,您可以删除提取后不再需要的文件,也不必在镜象中添加其他图层。 - Dockerfile最佳实践例如,你应该避免做以下事情:ADD https://example.com/big.tar.xz /usr/src/things/ RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things RUN make -C /usr/src/things all而是做一些像:RUN mkdir -p /usr/src/things \ && curl -SL https://example.com/big.tar.xz \ | tar -xJC /usr/src/things \ && make -C /usr/src/things all什么时候可以使用ADD如果<source>是具有可识别压缩格式的本地 tar存档,则它会自动解压缩为Docker镜像中的目录。例如:ADD rootfs.tar.xz /。这是Dockerfiles 中ADDover 的主要推荐用法COPY。对于不需要ADDtar自动提取功能的其他项目(文件,目录),应该始终使用COPY。
2019年01月13日
3,100 阅读
0 评论
0 点赞
2019-01-12
linuxea:白话容器之dockerfile CMD/entrypoint详解3(20)
此前的RUN和CMD,我们知道,RUN是构建的时候运行的命令,在镜像完成后RUN就运行结束。随后推送到仓库中,这些RUN命令是不会在进行运行的。- init在Docker上下文中,一个Docker只会运行一个应用程序,那么应该运行那个程序,又是什么应用?一般情况下,能拥有生产能力的应用通常在宿主机上一般表现是运行在后台守护进程程序,如:mysql,nginx等。这些服务在运行时候,都是以某个进程运行。某个进程都应该是某个进程的子进程,除init之外,而init是由内核启动的,一般我们在启动一个进程的时候,是以shell的子进程运行的,在命令行下创建的任何进程都是shell的子进程,而有一些经常也会直接占据shell的终端设备,就算使用&放置后台,启动的父进程也仍然是shell。进程终止的时候会将所有的子进程销毁,这种情况下我们会使用nohub command &,这样一来就类似于将启动的进程init那么在Docker中运行的init进程(init的id是1)是由内核启动,还是托管shell启 动。如果基于内核启动 ls /etc/* ,|等shell特性是无法使用的,那么如果基于shell启动,那init的id就不再是1了exec假如想基于shell的方式来启动一个主进程,那么shell的id号就是1,而后基于此在启动主进程,但是这样一来shell就不能退出,那可能需要一种能够剥离终端的方式启动,但是剥离了终端的方式启动,主进程号又不是1了。不过,我们可以使用exec来解决,shell启动是没有问题,进程号id是1也没有关系,exec顶替shell的id为1,取代shell进程,shell退出后exec就成了id为1的进程。在很多时候,在容器内启动一个应用程序的时候可以不基于shell,直接启动也可以,也可以基于shell,如果基于shell启动,并且不违背shell主进程id为1的调节关系,那么就可以使用第二种方式,exec。CMDRUN是构建的镜象build时候执行的,而cmd是定义一个镜象文件启动为容器时候默认要运行的程序,而Docker容器默认运行一个程序,在运行CMD的时候,是可以写多条CMD的,而最后一条CMD是生效的。而RUN是可以从上倒下接多RUN命令逐一运行。CMD类属于RUN命令,CMD指令也可以用于运行任何命令或应用程序,不过,二者的运行时间点不同RUN指令运行与映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动一个容器时CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且运行结束后,容器也将终止;不过,CMD指令的命令其可以被Docker run命令选项所覆盖在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效命令CMD <command> CMD ["<executable>","<paraml>","<param2>"] CMD ["<param1>","<param2>"]前两种语法格式的意义同RUN第一种的CMD的命令执行是直接写命令的,并且PID不为1,也无法接收信号(接收信号的必然是pid为1的超级管理进程),docker stop也无法停止。第二种直接启动为ID为1的进程,可接受处理shell信号的。第三种则用于ENTRYPOINT指令提供默认参数编写Dockerfile如,创建目录后追加文件,最后用CMD直接调用httpd启动FROM busybox LABEL maintainer="linuxea.com" app="CMD" ENV WEB_ROOT="/data/wwwroot" RUN mkdir -p ${WEB_ROOT} \ && echo '<h1> helo linuxea .</h1>' >> ${WEB_ROOT}/index.html CMD /bin/httpd -f -h ${WEB_ROOT}开始build[root@linuxEA /data/linuxea2]$ docker build -t marksugar/httpd:9 Sending build context to Docker daemon 2.048kB Step 1/5 : FROM busybox ---> 59788edf1f3e Step 2/5 : LABEL maintainer="linuxea.com" app="CMD" ---> Running in b6e91f2461dd Removing intermediate container b6e91f2461dd ---> 53559ed7015a Step 3/5 : ENV WEB_ROOT="/data/wwwroot" ---> Running in 3e615febfd44 Removing intermediate container 3e615febfd44 ---> a7917cb7ecbb Step 4/5 : RUN mkdir -p ${WEB_ROOT} && echo '<h1> helo linuxea .</h1>' >> ${WEB_ROOT}/index.html ---> Running in 15153c929109 Removing intermediate container 15153c929109 ---> 8e5548f3c00a Step 5/5 : CMD /bin/httpd -f -h ${WEB_ROOT} ---> Running in feeb34a9c423 Removing intermediate container feeb34a9c423 ---> a091b6d8a31d Successfully built a091b6d8a31d Successfully tagged marksugar/httpd:9从这里可以看到,这条启动命令是/bin/sh启动的子进程,在此后启动的时候会替换成id1,也就是默认执行exec将/bin/sh替换掉[root@linuxEA /data/linuxea2]$ docker inspect marksugar/httpd:9 ... "Cmd": [ "/bin/sh", "-c", "/bin/httpd -f -h ${WEB_ROOT}" ... 而后run起来,但是这里是没有交互式接口的,尽管使用了-it[root@linuxEA /data/linuxea2]$ docker run --name linuxea --rm -it marksugar/httpd:9 不过,可以使用exec进入容器,/bin/httpd -f -h /data/wwwroot的id为1我们在Dockerfile中直接使用命令的方式避免他不是1,那么这里就直接启动为1,默认执行力exec替换。这也就说明了,尽管使用-it仍然进入不了容器的原因,init1的进程不是shell。进入就要在使用exec绕过进入[root@linuxEA ~]$ docker exec -it linuxea sh / # ps aux PID USER TIME COMMAND 1 root 0:00 /bin/httpd -f -h /data/wwwroot 7 root 0:00 sh 13 root 0:00 ps aux / # 第二种格式CMD ["/bin/httpd","-f","-h ${WEB_ROOT}"]以这种方式进行buildFROM busybox LABEL maintainer="linuxea.com" app="CMD" ENV WEB_ROOT="/data/wwwroot" RUN mkdir -p ${WEB_ROOT} \ && echo '<h1> helo linuxea .</h1>' >> ${WEB_ROOT}/index.html #CMD /bin/httpd -f -h ${WEB_ROOT} CMD ["/bin/httpd","-f","-h ${WEB_ROOT}"]启动就会报错No such file[root@linuxEA /data/linuxea2]$ docker run --name linuxea --rm -it marksugar/httpd:10 httpd: can't change directory to ' ${WEB_ROOT}': No such file or directory报错No such file是因为CMD ["/bin/httpd","-f","-h ${WEB_ROOT}"]并不会运行成shell的子进程,而此变量是shell的变量,内核却不知道这个路径,所以会报错。不过,我们可以指定为shell,如: CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${WEB_ROOT}"]引言此前我们使用一条命令运行容器的时候,CMD的指令是可以被覆盖的,如下[root@linuxEA ~]$ docker run --name linuxea --rm -it marksugar/httpd:9 ls /etc group hosts mtab passwd shadow hostname localtime network resolv.conf上面这条命令是说,运行这个容器,ls /etc覆盖了此前镜像中的CMD中的启动httpd的命令。但是有时候我们不希望被覆盖,就使用ENTRYPOINTENTRYPOINT类似于CMD指令的功能,用于为容器指定默认的运行程序,从而使得容器像是一个单独的可执行文件与CMD不同的是由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指令的指定程序 不过,docker run命令--entrypoint选项参数可覆盖ENTRYPOINT指令指定的程序ENTRYPOINT <command> ENTRYPOINT ["<executable>","<param1>","<param2>"]docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后作为其参数使用Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个生效我们先编写一个Dockerfile,使用NETRYPOINT启动FROM busybox LABEL maintainer="linuxea.com" app="CMD" ENV WEB_ROOT="/data/wwwroot" RUN mkdir -p ${WEB_ROOT} \ && echo '<h1> helo linuxea .</h1>' >> ${WEB_ROOT}/index.html ENTRYPOINT /bin/httpd -f -h ${WEB_ROOT}而后build[root@linuxEA /data/linuxea2]$ docker build -t marksugar/httpd:11 . Sending build context to Docker daemon 2.048kB Step 1/5 : FROM busybox ---> 59788edf1f3e Step 2/5 : LABEL maintainer="linuxea.com" app="CMD" ---> Using cache ---> 53559ed7015a Step 3/5 : ENV WEB_ROOT="/data/wwwroot" ---> Using cache ---> a7917cb7ecbb Step 4/5 : RUN mkdir -p ${WEB_ROOT} && echo '<h1> helo linuxea .</h1>' >> ${WEB_ROOT}/index.html ---> Using cache ---> 8e5548f3c00a Step 5/5 : ENTRYPOINT /bin/httpd -f -h ${WEB_ROOT} ---> Running in 34c028efac0d Removing intermediate container 34c028efac0d ---> b7be6f74fc65 Successfully built b7be6f74fc65 Successfully tagged marksugar/httpd:11启动是没有问题的[root@linuxEA /data/linuxea2]$ docker run --name linuxea --rm -it marksugar/httpd:11我们获取到这个ip。访问试试[root@linuxEA ~]$ docker inspect -f {{.NetworkSettings.IPAddress}} linuxea 192.168.100.2[root@linuxEA ~]$ curl 192.168.100.2 <h1> helo linuxea .</h1>ENTRYPOINT而后使用CMD的方式同样来覆盖[root@linuxEA /data/linuxea2]$ docker run --name linuxea --rm -it marksugar/httpd:11 ls /etc容器依然运行起来,但我们并没有看到ls /etc的内容。这是因为在run的时候使用了ls /etc并不会替换Dockerfile中ENTRYPOINT的运行命令,只是在ENTRYPOINT命令之后加了ls /etc,而httpd识别不出ls /etc而已 如果一定要进行覆盖,就需要使用--entrypoint,如下:docker run --name linuxea --rm -it --entrypoint "/bin/ls" marksugar/httpd:11 -al /etc[root@linuxEA ~]$ docker run --name linuxea --rm -it --entrypoint "/bin/ls" marksugar/httpd:11 -al /etc total 28 drwxr-xr-x 1 root root 66 Dec 8 09:07 . drwxr-xr-x 1 root root 6 Dec 8 09:07 .. -rw-rw-r-- 1 root root 307 Sep 6 20:11 group -rw-r--r-- 1 root root 13 Dec 8 09:07 hostname -rw-r--r-- 1 root root 177 Dec 8 09:07 hosts -rw-r--r-- 1 root root 127 May 4 2018 localtime lrwxrwxrwx 1 root root 12 Dec 8 09:07 mtab -> /proc/mounts drwxr-xr-x 6 root root 79 Oct 1 22:37 network -rw-r--r-- 1 root root 340 Sep 6 20:11 passwd -rw-r--r-- 1 root root 114 Dec 8 09:07 resolv.conf -rw------- 1 root root 243 Sep 6 20:11 shadow示例ENTRYPOINT此时我们知道ENTRYPOINT是作为入口点的指令,通过exec 指定,指定的命令和参数作为一个JSON数组,那就意味着需要使用双引号而不是单引号ENTRYPOINT ["executable", "param1", "param2"]使用此语法,Docker将不使用命令shell,这意味着不会发生正常的shell处理。如果需要shell处理功能,则可以使用shell命令启动JSON数组。ENTRYPOINT [ "sh", "-c", "echo $HOME" ]另一种选择是使用脚本来运行容器的入口点命令。按照惯例,它通常在名称中包含入口点。在此脚本中,您可以设置应用程序以及加载任何配置和环境变量。下面是一个如何使用ENTRYPOINT exec语法在Dockerfile中运行它的示例。COPY ./docker-entrypoint.sh / ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["postgres"]例如,Postgres官方图像使用以下脚本作为其ENTRYPOINT:#!/bin/bash set -e if [ "$1" = 'postgres' ]; then chown -R postgres "$PGDATA" if [ -z "$(ls -A "$PGDATA")" ]; then gosu postgres initdb fi exec gosu postgres "$@" fi exec "$@"docker-compose 的写法:Docker Compose文件中使用的命令是相同的,除了使用小写字母。entrypoint: /code/entrypoint.sh可以在docker-compose.yml中使用列表定义入口点。entrypoint: - php - -d - zend_extension=/usr/local/lib/php/xdebug.so - -d - memory_limit=-1 - vendor/bin/phpunit不过仍然可可以使用docker run --entrypoint或docker-compose run --entrypoint标记覆盖入口的指令CMD/commandCMD(Dockerfiles)/ command(Docker Compose文件)的主要目的是在执行容器时提供默认值。这些将在入口点之后被附加到入口的参数。例如,如果运行docker run <image>,则将执行Dockerfiles中CMD/所指定的命令和参数command。在Dockerfiles中,可以定义CMD包含可执行文件的默认值。例如:CMD ["executable","param1","param2"]如果省略了可执行文件,则还必须指定一条ENTRYPOINT指令。CMD ["param1","param2"] (作为ENTRYPOINT的默认参数)注意:其中只能有一条CMD指令Dockerfile。如果列出多个CMD,则只有最后一个CMD生效。Docker Compose命令使用Docker Compose时,可以在docker-compose.yml中定义相同的指令,但它以小写形式写成完整的单词command。command: ["bundle", "exec", "thin", "-p", "3000"]覆盖CMD可以覆盖CMD运行容器时指定的命令。docker run rails_app rails console如果指定了参数docker run,那么它们将覆盖指定的默认值CMD。语法最佳实践还有EXEC语法,shell语法两个另一个有效的选项ENTRYPOINT和CMD。这将以字符串形式执行此命令并执行变量替换。ENTRYPOINT command param1 param2 CMD command param1 param2CMD应该几乎总是以形式使用CMD [“executable”, “param1”, “param2”…]。因此,如果镜象是用于服务的,例如Apache和Rails,那么你可以运行类似的东西CMD ["apache2","-DFOREGROUND"]`。实际上,建议将这种形式的指令用于任何基于服务的镜象。所述*ENTRYPOINT*shell形式防止任何*CMD*或*run*被使用命令行参数覆盖,但是有缺点,*ENTRYPOINT*将被开始作为一个子命令*/bin/sh -c*,其不通过信号。这意味着可执行文件将不是容器*PID 1*- 并且不会收到Unix信号 - 因此您的可执行文件将不会收到*SIGTERM*来自*docker stop <container>*如果*CMD*用于为*ENTRYPOINT*指令提供默认参数,则应使用JSON数组格式指定*CMD*和*ENTRYPOINT*指令。BothCMD和ENTRYPOINTinstructions指定运行容器时执行的命令。很少有规则描述它们如何相互作用。Dockerfiles应至少指定一个CMD或ENTRYPOINT命令。ENTRYPOINT 应该在将容器用作可执行文件时定义。CMD应该用作定义ENTRYPOINT命令的默认参数或在容器中执行ad-hoc命令的方法。CMD 在使用替代参数运行容器时将被覆盖。延伸阅读 :https://docs.docker.com/engine/reference/builder/ https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ https://docs.docker.com/engine/reference/builder/#usage https://docs.docker.com/compose/compose-file/ https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
2019年01月12日
3,894 阅读
0 评论
0 点赞
1
2
...
4