第二课 Docker践行DevOps理念-镜像和容器基本操作
tags:
- Docker
- 慕课网
categories:
- Docker
- Devlop实践
- Docker实验环境
- Image
- Container
- Dockerfile
- 上传容器
- 实战服务容器和工具容器
文章目录
第一节 Docker架构和实验环境
1.1 Docker Platform
- Docker提供了一个开发,打包,运行app的平台, 把app和底层infrastructure(可以直接物理,也可以虚拟机)隔离开来。
- docker engine 使我们docker中核心的东西。它包括
- 后台进程( dockerd ) ,用来维护后台常用的操作如:image,container容器管理,network网络,volume存储的管理
- REST API Server
- CLI接口( docker )
- 展示版本变成18.01.0-ce。通过ps -ef | grep docker可以看到dockerd的进程。如果没有,sudo systemctl restart docker
- 然后执行sudo docker version。本质上是docker客户端。
1.2 Docker架构
- docker底层技术支持
- Namespaces :做隔离pid, net, ipc, mnt, uts
- Control groups :做资源限制
- Union file systems : Container和image的分层
1.3 实验环境
- 提供dockerfile文件, shell自动执行脚本setup.sh和centos7的vagrant镜像。
- 插件用来共享数据到虚拟机(如果下不了,修改配置):
- vagrant plugin install vagrant-vbguest
- vagrant vbguest
- 如果安装插件后,启动一直卡在这Loading mirror speeds from cached hostfile。就不要同步文件夹啦,上面vbguest插件有问题。copy文件可以启动后使用vagrant-scp这个插件
- 安装: vagrant plugin install vagrant-scp
- 查看安装的插件:vagrant plugin list
- 加速插件安装:vagrant plugin install vagrant-scp --plugin-clean-sources --plugin-source https://gems.ruby-china.com/
- 使用vagrant global-status, 看下路径。
- 开启vagrant, 直接使用vagrant scp labs ~
- 如果卡在 Presto metadata available for base。不要激动。。。不是错误,等待完成即可
# Dockerfile
Vagrant.require_version ">= 1.6.0"
boxes = [
{
:name => "docker-host",
:eth1 => "192.168.205.10",
:mem => "1024",
:cpu => "1"
}
]
Vagrant.configure(2) do |config|
config.vm.box = "centos/7"
boxes.each do |opts|
config.vm.define opts[:name] do |config|
config.vm.hostname = opts[:name]
config.vm.provider "vmware_fusion" do |v|
v.vmx["memsize"] = opts[:mem]
v.vmx["numvcpus"] = opts[:cpu]
end
config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--memory", opts[:mem]]
v.customize ["modifyvm", :id, "--cpus", opts[:cpu]]
end
config.vm.network :private_network, ip: opts[:eth1]
end
end
# config.vm.synced_folder "./labs", "/home/vagrant/labs"
config.vm.provision "shell", privileged: true, path: "./setup.sh"
end
# 配置阿里镜像
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://eyzd1v97.mirror.aliyuncs.com"]
}
EOF
# 更新源
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum clean all
sudo yum makecache fast
sudo yum update
# 安装依赖包和docker
sudo yum install -y yum-utils device-mapper-persistent-data lvm2 git vim gcc glibc-static telnet bridge-utils net-tools
sudo yum install docker-ce-17.12.0.ce -y
sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker
# 添加vagrant到docker组中
sudo gpasswd -a vagrant docker # 把当前用户添加到docker组中
sudo systemctl restart docker.service # 重启docker服务
第二节 Docker Image初识
- 登录时vagrant使用docker都需要加上sudo,这样实在太麻烦啦。解决办法如下:
sudo groupadd docker # 默认已经有这个用户租了
sudo gpasswd -a vagrant docker # 把当前用户添加到docker组中
sudo systemctl restart docker # 重启docker服务
exit # 退出vagrant ssh 重新连接即可
2.1 Docker Image概述
- 文件和meta data的集合( root filesystem )
- 分层的,并且每一层都可以添加改变或删除文件,成为一个新的image
- 不同的image可以共享相同的layer
- Image本身是read-only的
2.2 获取dokcer Image
- 查看当前所有的image: sudo docker image ls
- 查看当前所有的image简写: docker images
- 获取docker Image方式一: Dockerfile
- docker build -t xiaopeng163/ redis: latest .
- . 代表从当前目录的dockerfile构建,-t 表示仓库名
FROM ubuntu:14.04 # 选择基础image
LABEL maintainer="Peng Xiao <[email protected]>" # 作者信息
RUN apt-get update && apt-get install -y redis-server # 镜像上运行命令
EXPOSE 6379 # 暴露端口
ENTRYPOINT ["/usr/bin/redis-server"] # 启动入口
- 获取docker Image方式二:Pull from Registry(从网上拉取)
- 例子:sudo docker pull ubuntu:14.04
- 官方Registry(公开免费): https://hub.docker.com/
- explore -> 镜像分为官方认证和个人的镜像。
2.3 构建自己的dokcer Image
- 通过c语言写一个hello-world程序,安装gcc
- docker image 可以看到一些常用命令。如:build pull history push rm ls
- docker image ls 简写 docker images
- docker image rm IMAGE ID简写 docker rmi IMAGE ID
mkdir hello-world
cd hello-world
vim hello.c
#include<stdio.h>
int main()
{
printf("hello docker world\n");
}
# 编译成二进制文件
gcc -static hello.c -o hello
# 创建Dockerfile文件
FROM scratch
ADD hello /
CMD ["/hello"]
# 构建自己的镜像 最后的. 表示在当前目录中找Dockerfile
docker build -t qnhyn/hello-world .
# 查看自己构建的镜像
docker image ls
docker history fce289e99eb9
# 执行镜像
docker run qnhyn/hello-world
第三节 Docker Container初识
3.1 Container简介
- Container通过Image创建( copy )
- 在Image layer之.上建立一个container layer (可读写)
- Image和Contaner的关系。类比面向对象:类和实例
- Image负责app的存储和分发, Container负责运行app
3.2 Container基本操作
- 查看正在运行的Container: docker container ls
- 查看所有(正在运行和已经运行的)的Container: docker container ls -a
- 查看所有(正在运行和已经运行的)的Container简写方式:docker ps -a
- docker container rm + CONTAINER ID 简写 docker rm + CONTAINER ID
- docker container可以看到常用命令。
- 交互式运行 -i,–interactive
- 移除掉所有的container: docker rm $( docker container ls -aq)
- **移除掉所有的退出状态的container:**docker rm $(docker container ls -f “status=exited” -q)
# 运行一个container 这种方式运行完就退出啦
docker run centos
# 交互式运行 -i,--interactive
docker run -it centos
# 可以用yum安装软件 touch创建文件
# exit 退出
# 删除container docker container rm + ContainerID(写全或者写一些都可以找到)
docker container rm b27fe3deb674
docker container ls -a
docker rm 2be
docker ps -a
# 只查看container的ID
docker container ls -aq
docker container ls -a | awk {'print$1'}
# 移除所有的container
docker rm $( docker container ls -aq)
# 查看退出状态的所有容器
docker container ls -f "status=exited"
# 删除所欲退出状态的容器
docker container rm $(docker container ls -f "status=exited" -q)
3.3 Container构建image
- 基于image创建container, 在container里面做一些变化(比如:安装一些软件)。然后在把变化后的Containre重新commit成image.
- 上述过程:docker container commit 简写 docker commit
- 这种方式构建出的image,自己用没问题。如果是给别人用或者用别人的,可能镜像中可能安装一些不安全的软件,所以不推荐这种方式构建image.
# 交互式创建一个container容器
docker run -it centos
# 在centos中安装vim
yum -y install vim
# 退出container
exit
# 把修改后的container commit 成image
# 用法:docker commit container名称 (库:版本)
docker ps -a # 查看container名称
docker commit loving_swanson qnhyn/centos-vim
# 查看构建的image
docker image ls
# 查看共享层 b48是centos原来镜像id, 47是修改后镜像id
docker history b48
docker history 47
3.4 Dockfile构建image
- 我们一般推荐这种Dockfile的方式构建image镜像。(只需共享Dockerfile文件,就可以构建和我一样的环境)
- docker build -t hynqn/centos-vim-new .
- 这里需要说明一下,我们的镜像是只读的如何修改呢。
- 通过上面构建过程可以看出,它其实在构建过程中生成了一个临时的container
- 在临时的 container 运行yum安装
- 然后临时container Commit成一个新的镜像
- 删除临时container
- 过程如下
mkdir docker-centos-vim
cd docker-centos-vim
vim Dockerfile
FROM centos
RUN yum -y install vim
# 构建镜像
docker build -t hynqn/centos-vim-new .
第四节 Dockerfile语法梳理和最佳实践
- 官方文档: https://docs.docker.com/engine/reference/builder/
4.1 Dockerfile 常用关键字
- 关键字FROM。选择基础镜像(不需要镜像,选择scratch)
- FROM scratch #制作base image
- FROM centos #使用base image
- FROM ubuntu:14.04
- 关键字:LABEL 。定义了image的Metadata(基础信息)
- LABEL maintainer= " [email protected] # 作者
- LABEL version= “1.0” # 版本
- LABEL description= “This is description” # 描述
- 关键字:RUN 。用于临时容器运行命令,后打包生成到新容器
- 每一条RUN, 都会产生新的一层Image layer
- 为了美观,复杂的RUN请用反斜线换行!
- 避免无用分层,合并多条命令成一行
RUN yum update && yum install -y vim \
python-dev #反斜线换行
RUN apt-get update && apt-get install -y perl \
pwgen --no-install-recommends && rm -rf \
/var/lib/apt/lists/* #注意清理cache
RUN /bin/bash -C 'source $HOME/.bashrc; echo $HOME'
- 关键字:WORKDIR。 设定当前工作目录 WORKDIR /root
- 用WORKDIR,**不要用RUN cd **
- 尽量使用绝对目录
WORKDIR /test #如果没有会自动创建test目录
WORKDIR demo
RUN pwd #输出结果应该是/test/demo
- 关键字: ADD and COPY
- ADD 把本地文件添加到Docker Image中
- ADD 不光可以拷贝文件到指定目录中,它还可以解压缩
- 大部分情况, COPY优于ADD
- ADD除了COPY还有额外功能(解压)
- 添加远程文件/目录请使用curl或者wget
ADD hello /
ADD test.tar.gz / #添加到根目录并解压
WORKDIR /root
ADD hello test/ # /root/test/hello
WORKDIR /root
COPY hello test/
- 关键字: ENV 通过设置环境变量设置常量
ENV MYSQL VERSION 5.6 # 设置常量
RUN apt-get install -y mysql-server= "${MYSQL_ _VERSION}” \
&& rm -rf /var/lib/apt/lists/* # 引用常量
- 关键字:VOLUME 和EXPOSE
- (存储和网络) 看后面章节具体详讲。
- 关键字:CMD 和 ENTRYPOINT
- 下面一下节细讲
4.2 CMD和ENTRYPOINT
- RUN :执行命令并创建新的Image Layer
- CMD :设置容器启动后默认执行的命令和参数
- 容器启动时默认执行的命令
- 如果docker run指定了其它命令, CMD命令被忽略
- 如果定义了多个CMD ,只有最后一个会执行
# Dockerfile
FROM centos
ENV name Docker
CMD echo "hello $name"
# /bin/bash 会把CMD的命令覆盖掉
docker run -it qnhyn/centos-cmd-shell /bin/bash
- ENTRYPOINT :设置容器启动时运行的命令(使用最多)
- 让容器以应用程序或者服务的形式运行
- 不会被忽略, 一定会执行
- 最佳实践:写一个shell脚本作为entrypoint
# 写一个shell脚本作为entrypoint
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
- shell 格式
# Shell格式
RUN apt-get install -y vim
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"
# Dockerfile1例子
FROM centos
ENV name Docker
ENTRYPOINT echo "hello $name" #输出hello Docker
- EXEC格式
# Exec格式
RUN ["apt-get", "install", "-y", "vim"]
CMD ["/bin/echo", "hello docker"]
ENTRYPOINT ["/bin/echo", "hello docker"]
# Dockerfile2例子 docker build -t qnhyn/centos-entrypoint-exec-new .
FROM centos
ENV name Docker
# ENTRYPOINT ["/bin/echo", "hello $name"] # 输出hello $name
# 指明命令通过bash执行,才可以解析上面变量
ENTRYPOINT ["/bin/bash", "-c", "echo hello $name"] #输出hello Docker
4.3 Dockerfile镜像的发布
- Docker官方仓库注册账号密码:https://hub.docker.com/
- 方式一:我们提交仓库的时候: 账号/image名字 — 直接提交镜像(不推荐,因为不安全呀)
# 登录docker仓库
docker login # 输入账号密码 返回success 表示登录成功
# docker image push 简写 docker push
docker push qnhyn/hello-world:latest
-
方式二:我们提交我们的Dockerfile文件,到Github或者是Bitbuacket。然后让Docker仓库网站帮我们构建镜像。(推荐这种方式,安全)
- 绑定你Github账号到docker官网上
- 我们只需要维护Dockerfile就可以啦
-
如果是公司使用,不想让自己的镜像公开。Docker官方也给我们提供了,建立私有Registery的镜像。用来搭建自己的仓库服务器
# 创建另一台网络可达的虚拟机
# 启动私有的Registry
docker run -d -p 5000: 5000 --restart always --name registry registry:2
# 测试可达
telnet 服务器IP(10.75.44.222) 5000
docker build -t 服务器IP(10.75.44.222):5000/hello-world
# 配置可信信息
sudo ls /etc/docker
sudo more /etc/docker/daemon.json
vim /etc/docker/daemon.json
# 写入可信信息
{"insecure-registries":["10.75.44.222:5000"]}
sudo vim /lib/systemd/system/docker.service
# 加入一行
EnvironmentFile=-/etc/docker/daemon.json
sudo service docker restart
# 提交到服务器
docker push 服务器IP(10.75.44.222):5000/hello-world
# Registry服务器 验证提交是否成功 官方文档:https://docs.docker.com/registry/spec/api/
# 浏览器输入: 可以看到json数据
服务器IP 10.75.44.222:5000/v2/_catalog
第五节 Dockerfile实战
5.1 通过docker创建flask服务
- 创建app.py
- 安装pip:
- sudo yum -y install epel-release
- sudo yum -y install python-pip
- sudo pip install flask -i https://pypi.douban.com/simple
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "hello docker"
if __name__=='__main__' :
app.run()
- 宿主机访问虚拟机的WEB服务。需要修改虚拟机网络为 public network, bridge(桥接模式),查看虚拟机的IP并访问(通过virtualbox登录查看),虚拟机的IP与宿主机的IP为同一网段。
- 也可以使用:curl http://172.0.0.1:5000 来访问服务
- 写Dockerfile。构建自己的镜像 docker build -t qnhyn/flask-hello-world .
- 如果构建失败, 我们可以交互式进入到生成的临时容器中进行调试。
- docker run -it 4320f8b526bc bin/bash
FROM python:2.7
LABEL maintainer="qnhyb<[email protected]>"
RUN pip install flask
COPY app.py /app/
WORKDIR /app
EXPOSE 5000
CMD ["python", "app.py"]
- 创建镜像,运行容器(后台运行 -d)
- docker run -d qnhyn/flask-hello-world
- 进入到容器中。docker exec -it 11a767d3a588 /bin/ bash
ps -ef | grep python
# 进入python交互界面
docker exec -it 11a767d3a588 python
docker exec -it 11a767d3a588 ip a
# 停止运行中的容器
docker container stop 11a767d3a588
docker stop 11a767d3a588
# 清理退出的所有容器
docker rm $(docker ps -aq)
# 给容器起一个名字并启动
docker run -d --name=demo qnhyn/flask-hello-world
docker stop demo
# 显示容器的详细信息
docker inspect 11a767d3a588
# 显示容器运行日志
docker logs 11a767d3a588
5.2 通过docker构建linux工具stress
- 工具stress 的使用
docker run -it ubuntu
#安装stress。
apt-get update && apt-get install -y stress
which stress
stress --help
# --vm 创建几个worker(进程) verbose debug输出
stress --vm 1 --verbose # 创建一个进程,分配250M,在释放。一直循环
stress --vm 1 --vm-bytes 500000M --verbose # 最大不能超过宿主机的内存
- 写Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y stress
ENTRYPOINT ["/usr/bin/stress"]
CMD [] # 用来接收docker run 后面的参数
- 构建镜像,运行容器
# 构建
docker build -t qnhyn/ubuntu-stress .
# 直接运行不加参数
docker run -it qnhyn/ubuntu-stress
# 加参数运行
docker run -it qnhyn/ubuntu-stress --vm 1 --verbose
- 限制容器使用资源
# 限制内存
# 设置容器内存为200M 加上swap内存(不设置和memory一样) 共400M
docker run --memory=200M qnhyn/ubuntu-stress --vm 1 --verbose
# 500>400 报错内存不够
docker run --memory=200M xi qnhyn/ubuntu-stress --Vm 1 --verbose --Vm-bytes 500M
# 限制CPU --cpu-shares相对权重
# 假如连个容器,一个设置为10,一个设置为5。那么第一个容器就占用虚拟机内存的2/3
docker run --cpu-shares=10 --name=test1 qnhyn/ubuntu-stress --cpu 1
docker run --cpu-shares=5 --name=test2 qnhyn/ubuntu-stress --cpu 1
# top 查看资源占用
top
- 资源的限制源于底层的技术支持
- Namespaces :做隔离pid, net, ipc, mnt, uts
- Control groups :做资源限制
- Union file systems : Container和image的分层