docker-01-基操

2020-08-10  本文已影响0人  西海岸虎皮猫大人

1.docker基本操作

# 查看docker是否正常工作
docker info
# 运行一个容器
# -i 保证stdin是开启的
# -t 为容器分配一个伪终端
# docker会检查本地是否存在镜像,如否则从官方下载
docker run -i -t ubuntu /bin/bash

# 容器中执行,容器主机名即容器id
hostname
# hosts文件为该容器的ip配置了一条主机配置
cat /etc/hosts
# 查看容器进程
ps -aux
# 容器中安装软件
apt-get update && apt-get install vim
# 退出容器
exit

# 退出容器后容器停止运行,但容器依然存在
# 列出容器
# -a参数可以查看已经停止的容器
# -l列出最后一个运行的容器
# --format 进一步控制显示哪些及如何显示信息
docker ps -a

# 给容器命名,容器的名称有助于从逻辑上理解容器与应用程序的连接关系,推荐使用
docker run --name vincent_container -i -t ubuntu /bin/bash
exit

# 启动已经停止运行的容器,也可以通过id启动
# 也可使用docker restart重新启动容器
docker start vincent_container
# 查看运行的docker容器
docker ps

# 重新附着到正在运行的容器(进入容器shell),也可通过id附着
docker attach vincent_container

# 启动守护式容器,适合运行应用程序和服务,大多数时候需要守护式
# -d参数 后台运行
# 循环打印hello world直到容器停止
docker run --name daemon_dave -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"

# 获取守护式容器的日志
docker logs daemon_dave
# 类似tail -f跟踪日志
docker logs -f daemon_dave
# 退出跟踪
ctrl + c
# 获取日志最后10行内容
docker logs --tail 10 daemon_dave
# 跟踪日志最新内容
docker logs --tail 0 -f daemon_dave
# 日志加时间戳
docker logs -ft daemon_dave

# 使用日志驱动
# syslog选项禁用docker logs,将所有的容器日志都输出到Syslog
# 另一个可用选项是none,将禁用所有容器中的日志
docker run --log-driver="syslog" --name daemon_dwayne -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"

# 查看守护容器中的进程
docker top daemon_dave
# 显示一个或多个容器的统计信息
# 显示CPU 内存 网络io 磁盘io,对快速监控一台主机上的一组容器非常有用
docker stats daemon_dave daemon_dwayne

# 容器中运行后台任务
# -d 表示运行一个后台进程
docker exec -d daemon_dave touch /etc/new_config_file
# 容器内运行交互式任务
# -i -t创建tty并捕捉stdin
docker exec -t -i daemon_dave /bin/bash
# 停止容器
docker stop daemon_dave
# 显示最后3个容器,不论容器运行还是停止
docker ps -n 3

# 自动启动容器
# --restart设置为always,无论容器的退出代码是什么,docker都会自动重启该容器
# 设置为on-failure则只有退出代码非0值时才会重启
# --restart=on-failure:5,最多重启5次
docker run --restart=always --name daemon_dd -d ubuntu /bin/bash -c "while true; do echo hello world; sleep 1; done"

# 获取容器的更多信息
# inspect 对容器进行详细的检查,返回配置信息,包括名称\命令\网络配置等
docker inspect daemon_dave

# 有选择地获取容器信息
# 返回容器的运行状态
docker inspect --format='{{ .State.Running }}' daemon_dave
# 查看容器的ip地址
docker inspect --format='{{ .NetworkSettings.IPAddress }}' daemon_dave
# --format支持完整的go语言模板,可以充分利用go语言优势
# 指定多个容器
docker inspect --format '{{ .Name }} {{ .State.Running }}' daemon_dave daemon_dd

# 可以通过浏览 /var/lib/docker深入了解docker,该目录存放docker镜像\容器及容器的配置,所有的容器保存在 /var/lib/docker/containers目录下

# 删除容器,删除运行中的容器会报错,需要先停止
docker rm 3ff1695dda4f
# 删除运行中容器
docker rm -f 3ff1695dda4f
# 无法删除所有容器,但可以通过以下技巧
# -a 列出所有容器 -q只返回容器id 从而得到容器id的列表
docker rm `sudo docker ps -a -q`

2.docker镜像和仓库

最底端是引导文件系统-bootfs,容器启动后加到内存中,bootfs被卸载;
第二层是root文件系统-rootfs,最先以只读方式加载,引导结束并完成完整性检查后切换为读写模式,但在docker里rootfs永远是只读,docker利用联合加载技术在rootfs上加载更多的只读文件系统;
联合加载指一次加载多个文件系统,但在外面看起来只是一个文件系统;
docker把这样的文件系统称为镜像,一个镜像可以放到另一个镜像底部,称为父镜像,最底层称为基础镜像,最顶层加载一个读写文件系统,docker运行的程序就是在这个读写层中进行;
内核-> 引导文件系统-> 基础镜像(ubuntu)-> 镜像(加入apache) -> 可写容器;
docker第一次启动容器,读写层为空;文件系统发生变化时,变化会应用到此层;如果修改一个文件,文件首先被该读写层下面的只读层复制到该读写层;该文件的只读副本依然存在,但已经被隐藏;这种机制称为写时复制(copy on write),这也是是docker如此强大的技术之一.

# 列出docker镜像
docker images
# ubuntu镜像保存在仓库中,仓库在Registry中
# 默认的Registry是Docker公司运营的Docker Hub
# 拉取ubuntu镜像
docker pull ubuntu:12.04
# 查看拉取的镜像
docker images
# tag(12.04)机制使得统一仓库可以存储多个镜像
# 运行一个带标签的镜像
docker run -t -i --name new_container ubuntu:12.04 /bin/bash
# 构建容器时指定标签是一个好习惯
# docker hub有两种类型的仓库:用户仓库和顶层仓库
# 用户仓库由用户名和仓库名组成,如vincent/puppet
# 顶层仓库只包含仓库名,镜像是架构良好\安全\最新的
# 使用docker run启动容器模式使用latest标签
# 拉取fedora镜像
docker pull fedora:20
# 查看fedora镜像
docker images fedora
# 查找镜像
# stars 反映一个镜像的受欢迎程度
# official 是否官方,表示是否由上游开发者管理
# automated 表示镜像是docker hub自动构建流程构建
docker search puppet
# 拉取镜像,下载镜像到本地(预装了puppet服务器)
docker pull macadmins/puppetmaster
# 构建容器
docker run -i -t macadmins/puppetmaster /bin/bash

# 构建镜像
# 两种方法:
# 1.docker commit
# 2.docker build和Dockerfile文件
#  不推荐使用docker commit,后者更灵活
# 登录docker hub,这里使用阿里云
docker login --username=wu_peizhen@126.com registry.cn-beijing.aliyuncs.com
# 用户信息保存在 $HOME/.docker/config.json
# 创建一个定制容器
# 安装apache
apt-get update -y
apt-get install apache2 -y
# 注意docker ubuntu镜像下载软件没有使用阿里云镜像,需要手动配置
# 默认没有vi和vim需要手动安装,但配置了阿里云重新安装apache2提示,
# Unable to correct problems, you have held broken packages
# 需要切换回官方镜像,重新安装...

# 提交定制容器
docker commit c22d8ab8d6a9 vincent_wu/apache2
# 然而aliyun中并没有找到自己的镜像...
# 检查新创建的镜像
docker images vincent_wu/apache2
# 提交另一个新的定制容器,指定更多的数据(包括标签)
# -m 指定提交信息
# -a 指定作者信息
# tag webserver
docker commit -m"A new custom image" -a"Vincent Wu" c22d8ab8d6a9 vincent_wu/apache2:webserver
# 查看提交的镜像详细信息
docker inspect vincent_wu/apache2:webserver
# 从提交的镜像运行一个容器
docker run -t -i vincent_wu/apache2:webserver /bin/bash

# 使用dockerfile构建镜像(推荐)
# 创建一个实例仓库

---------
# Version: 0.0.1
FROM ubuntu:14.04
MAINTAINER Vincent Wu "wu_peizhen@126.com"
RUN apt-get update && apt-get install -y nginx
RUN echo 'Hi, I am in your container' > /usr/share/nginx/html/index.html
EXPOSE 80
---------
# 基于Dockerfile构建新镜像, 注意点号(略慢)
# 默认标签为lastest
docker build -t="vincent_wu/static_web" .
# 指定标签
docker build -t="vincent_wu/static_web:v1" .
# 从Git仓库构建
docker build -t="vincent_wu/static_web:v2" git@gitee.com:iacs/static_web
# 异常 TODO
unable to prepare context: unable to 'git clone' to temporary context directory: error fetching: ssh_exchange_identification
# 如构建失败,比如nginx名称填错,可以使用docker run基于这次构建创建一个容器,手动install

# 构建缓存
# 每一步都会将结果提交为镜像,会将之前的镜像层看做缓存
# 略过缓存功能
docker build --no-cache -t="vincent_wu/static_web" .

# 基于构建缓存的Dockerfile模板
# REFRESHED_AT 环境变量表示模板最后更新时间
# 修改这个时间即可刷新apt包的缓存
--------
FROM ubuntu:14.04
MAINTAINER Vincent Wu "wu_peizhen@126.com"
ENV REFRESHED_AT 2020-08-10
RUN apt-get update
--------
# 查看镜像的构建方式
docker history d662f2ba3294
# 基于新构建镜像启动一个容器
# 以前台方式启动nginx
# -p 指定docker运行时公开给外部的网络端口
# 可以在宿主机随机选择32768-61000的一个比较大的端口映射到容器中的80端口,也可以指定具体端口号
docker run -d -p 80 --name static_web vincent_wu/static_web nginx -g "daemon off;"
# 查看docker端口映射
docker ps -l
# 查看指定容器id\端口的映射(报错),也可使用容器名
docker port dbb83ce44d00 80
# 映射到宿主机指定端口,这样会限制灵活性(只有一个容器能成功绑定),可以绑定到不同的宿主机端口
docker run -d -p 80:80 --name static_web vincent_wu/static_web nginx -g "daemon off;"
# 绑定到特定的网络接口
docker run -d -p 127.0.0.1:80:80 --name static_web vincent_wu/static_web nginx -g "daemon off;"
# 绑定到随机端口
docker run -d -p 127.0.0.1::80 --name static_web vincent_wu/static_web nginx -g "daemon off;"
# -P参数可以对外公开Dockerfile中EXPOSE指令公开的所有端口(绑定到宿主机的随机端口)
docker run -d -P --name static_web vincent_wu/static_web nginx -g "daemon off;"
# 使用curl连接到容器(异常)
curl localhost:8080
Dockerfile指令
# CMD
# 指定一个容器启动时要运行的命令,类似于docker run
CMD ["/bin/true"]
# 给CMD命令传递参数,推荐使用数组
CMD ["/bin/bash", "-l"]
# 使用docker run命令会覆盖CMD命令

# ENTRYPOINT
# 与CMD类似,但不会被docker run覆盖,docker run指定的参数会传递给ENTRYPOINT指定的命令
ENTRYPOINT ["/usr/sbin/nginx"]
# 指定参数
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]
# 通过ENTRYPOINT和CMD组合完成巧妙的工作
# 可以指定-g "daemon off;"参数让守护进程以前台方式运行
# 如果启动容器不指定参数,则CMD命令中的-h会被传递给守护进程
# 这是我们可以运行一个默认的命令,同时支持通过docker run命令覆盖该命令
ENTRYPOINT ["/usr/sbin/nginx"]
CMD ["-h"]

# WORKDIR
# 创建容器时设置一个工作目录,ENTRYPOINT和CMD都在这个目录中执行
# 切换/opt/webapp/db目录执行bundle install,切换/opt/webapp目录执行rackup
WORKDIR /opt/webapp/db
RUN bundle install
WORKDIR /opt/webapp
ENTRYPOINT ["rackup"]
# 覆盖工作目录
docker run -ti -w /var/log ubuntu pwd

# ENV
# 镜像构建过程中设置环境变量
ENV RVM_PATH /home/rvm
RUN gen install unicorn
# 使用ENV设置多个环境变量
ENV RVM_PATH=/home/rvm RVM_ARCHFLAGS="-arch i386"
# 在其他指令中使用环境变量
ENV TARGET_DIR /opt/app
WORKDIR $TARGET_DIR 
# 容器中使用env命令可以看到设置的环境变量
env
# docker run -e传递环境变量,只在运行时有效
docker run -ti -e "WEB_PORT=8080" ubuntu env

# USER
# 指定该镜像会以什么样的用户去运行
USER NGINX
# 可以指定用户名或UID以及组或GID(各种组合)
USER user:group
USER uid:gid
# 可在docker run命令中通过-u覆盖该指定指定的值

# VOLUME
# 为容器添加卷
# 卷可以存在于一个或多个容器,提供共享数据或持久化功能
# 对卷的修改立即生效
# 通过卷可将源代码\数据库等添加到镜像中,允许多容器间共享,可以利用此功能测试代码,管理日志,处理数据库等
VOLUME ["/opt/project"]
# docker cp和VOLUME指令相关,从容器复制文件或者复制文件到容器中
# 可指定多个卷
VOLUME ["/opt/project", "/data"]

# ADD
# 将构建环境下的文件和目录复制到镜像中
# 比如安装应用时,指定源文件位置和目标文件位置
# 不能对构建目录或者上下文之外的文件ADD
# 通过末尾字符判断是目录还是文件, / 就认为是目录,否则文件
ADD software.lic /opt/application/software.lic
# 文件源可以使用url的方式
ADD http://wordpress.org/latest.zip /root/wordpress.zip
# 如果将归档文件指定为源文件,docker会自动将归档文件解开
# 目的文件位置不存在会创建全路径

# COPY
# COPY复制,不做文件提取和解压
# 源路径是与构建环境相对的路径,目标路径是容器中的绝对路径
COPY conf.d/ /etc/apache2/

# LABEL
# 为docker镜像添加元数据,键值对的形式
# 推荐所欲元数据放到一条LABEL指令中,方式不同的指令创建过多镜像层
LABEL version="1.0"
LABEL location="Qing Dao" type="Data Center" role="Web Server"
# 通过docker inspect可以查看标签信息

# STOPSIGNAL
# 停止容器时发什么系统调用信号给容器

# ARG
# 定义可以在docker build命令运行时传递给构建运行时的变量
ARG build
ARG wepapp_user=user
# 设置build变量,wepapp_user使用默认值
docker bulid --build-arg build=1234 -t vincent_wu/webapp .
# 不建议使用ARG传递证书或秘钥,构建历史会暴露
# 预定义ARG变量HTTP_PROXY等不用再定义

# ONBUILD
# 为镜像添加触发器
# 在构建过程添加新指令
ONBUILD ADD . /app/src
ONBUILD RUN cd /app/src && make
# 可通过docker inspect查看

# 镜像推送到docker hub(这里使用阿里云, 私有仓库收费)
docker push vincent_wu/static_web
# 异常
denied: requested access to the resource is denied

# 自动构建
# 将github中连接到Docker Hub,推送代码触发构建活动
# Docker Hub -> 个人信息 -> Add Repository

# 删除镜像
docker rmi vincent_wu/static_web
# 异常
Error response from daemon: conflict: unable to remove repository reference "vincent_wu/static_web" (must force) - container 66dd9dcfc09c is using its referenced image d662f2ba3294
# 可以指定多个镜像名删除多个镜像 空格隔开

# 运行基于容器的Registry,构建不想被公开的信息或数据
docker run -p 5000:5000 registry:2
# 异常: 关于insecure-registry

3.在测试中使用docker

3.1 测试静态网站

mkdir sample && cd sample
# 编写Dockerfile
vi Dockerfile

------
FROM ubuntu:14.04
MAINTAINER Vincent Wu "wu_peizhen@126.com"
ENV REFRESHED_AT 2014-O6-01
RUN apt-get -y update && apt-get -y install nginx
RUN mkdir -p /var/www/html/website
ADD nginx/global.conf /etc/nginx/conf.d/
ADD nginx/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
------

# nginx配置文件
mkdir nginx && cd nginx
vi global.conf

-------
server {
        listen  0.0.0.0:80;
        server_name     _;
        root    /var/www/html/website;
        index   index.html index,htm;
        access_log      /var/log/nginx/default_access.log;
        error_log       /var/log/nginx/default_error.log;
}

-------

vi nginx.conf

-------
user www-data;
worker_processes 4;
pid /run/nginx.pid;
daemon off;
events { }

http{
        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        include /etc/nginx/mime.types;
        default_type application/octet-stream;
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;
        gzip_disable "msie6";
        include /etc/nginx/conf.d/*.conf;
}
-------
cd ..

# 构建镜像
docker build -t vincent_wu/nginx .
# 查看构建历史
docker history vincent_wu/nginx
# 创建html文件目录和文件
mkdir website && cd website
vi index.html

------------
hello docker
------------

# 启动容器 
# -v将宿主机目录作为卷挂载到容器中
# 容器启动后,修改website/index.html文件立即生效
docker run -d -p 80 --name website -v $PWD/website:/var/www/html/website vincent_wu/nginx nginx
# 只读 加:ro
# docker run -d -p 80 --name website -v $PWD/website:/var/www/html/website:ro vincent_wu/nginx nginx
# 查看容器
docker ps -l
# 访问: http://192.168.68.141:32769/

3.2 测试web应用程序

mkdir sinatra && cd sinatra
vi Dockerfile
-------------
FROM ubuntu:18.04
LABEL maintainer="james@example.com"
ENV REFRESHED_AT 2014-06-01

RUN apt-get -y update && apt-get -y install ruby ruby-dev build-essential redis-tools
RUN gem install --no-rdoc --no-ri sinatra json redis

RUN mkdir -p /opt/webapp

EXPOSE 4567

CMD [ "/opt/webapp/bin/webapp" ]
-------------
# 下载sinatra源码放到webapp目录
# 赋执行权限
chmod -x webapp
# 启动容器
docker run -d -p 4567 --name webapp -v $PWD/webapp:/opt/webapp vincent_wu/sinatra
# 查看日志
docker logs webapp
# 跟踪日志
docker logs -f webapp
# 查看容器中进程
docker top webapp
# 查看端口映射
docker port webapp 4567
# 测试
curl -i -H 'Accept: application/json' -d 'name=Foo&status=Bar' http://localhost:49160/json

3.3 使用redis

# 下载webapp_redis
# 赋权
chmod +x webapp_redis/bin/webapp
# 为redis容器创建目录
mkdir -p redis && cd redis
vi Dockerfile
----------
FROM ubuntu:14.04
LABEL maintainer="james@example.com"
ENV REFRESHED_AT 2014-06-01

RUN apt-get  update && apt-get -y install redis-server redis-tools

EXPOSE 6379

ENTRYPOINT ["/usr/bin/redis-server" ]
CMD []
----------
# 构建redis镜像
docker build -t  vincent_wu/redis .
# 启动redis容器
docker run -d -p 6379 --name redis vincent_wu/redis 
# 查看端口映射
docker port redis 6379
# 测试redis连接
# ubuntu安装redis客户端
apt-get -y install redis-tools
# 测试redis连接
redis-cli -h 127.0.0.1 -p 49161

# sinatra连接到redis
# 3种方法:
# 1.docker内部网络,不灵活
# 2.docker network命令, 1.9之后版本推荐使用
# 3.docker链接 将具体容器链接到一起来通信的抽象层
# network可以将容器连接到不同宿主机,停止\启动\重启无需更新连接,不必事先创建容器再去连接

# 1.通过内部网络连接redis
########
# 查看docker网络接口
ip a show docker0
# docker0是一个虚拟的以太网桥,用于连接容器和本地宿主网络
# 查看redis容器网络配置
docker inspect redis
# 只查看redis容器ip
docker inspect redis -f '{{.NetworkSettings.IPAddress}}' redis
# 直接与redis容器通信
redis-cli -h 172.17.0.4
# 这种方式有两个问题,一是需要对redis容器ip硬编码,而是如果重启容器ip会改变
# 重启redis
docker restart redis
# 查看ip,貌似并无变化...版本问题?
########

# 2.通过networking连接
######################
# docker networking允许用户创建自己的网络
# networking也和docker compose以及swarm进行了集成
# 创建docker网络,桥接网络,命名app
docker network create app
# 查看网络
docker network inspect app
# 列出当前系统所有网络
docker network ls
# 删除docker网络
# docker network rm app
# 在docker网络中创建redis容器
# --net指定网络
docker run -d --net=app --name db vincent_wu/redis
# 再次运行inspect可以看到容器信息
docker network inspect app
# 启动连接了redis的web容器
docker run -p 4567 --net=app --name webapp -it -v $PWD/webapp:/opt/webapp vincent_wu/sinatra /bin/bash
# 查看该容器配置
cat /etc/hosts
# ping redis容器
ping db.app
# 容器中启动应用程序,以后台方式运行
nohup /opt/webapp/bin/webapp &
# 检查端口映射
docker port webapp 4567
# 测试
curl -i -H 'Accept: application/json' -d 'name=Foo&status=Bar' http://locahost:49161/json
# 连接redis,查看params键
# 将已有容器连接到docker网络
docker network connect app db2
docker network inspect app
# 从网络中断开一个容器
docker network disconnect app db2
####################

# 构建jenkins
mkdir jenkins && cd jenkins
vi Dockerfile
-----------
FROM jenkins/jenkins:lts
MAINTAINER james@example.com
ENV REFRESHED_AT 2016-06-01

USER root
RUN apt-get -qq update && apt-get install -qq sudo
RUN echo "jenkins ALL=NOPASSWD: ALL" >> /etc/sudoers
RUN wget http://get.docker.com/builds/Linux/x86_64/docker-latest.tgz
RUN tar -xvzf docker-latest.tgz
RUN mv docker/* /usr/bin/

USER jenkins
RUN /usr/local/bin/install-plugins.sh junit git git-client ssh-slaves greenballs chucknorris ws-cleanup
-----------
# 获取dockerjenkins.sh脚本
# 赋权
chmod 0755 dockerjenkins.sh
# 构建
docker build -t vincent_wu/dockerjenkins .
# 运行
# --privileged 启动docker特权模式,以宿主机具有的(几乎)所有能力,有安全风险
docker run -p 8080:8080 --name jenkins --privileged -d vincent_wu/dockerjenkins
# 日志
docker logs jenkins
# 访问jenkins
# TODO
# 创建jenkins作业
# 运行jenkins作业
上一篇 下一篇

猜你喜欢

热点阅读