DockerDocker其他开发工具

Docker:容器管理(启动参数,查看容器和日志,进入和修改容器

2021-06-25  本文已影响0人  xiaogp

摘要:Docker

容器概念基础

容器是一个精简版的操作系统,一般一个容器只运行一个应用,容器通过镜像创建,使用 docker run命令创建,容器起到了隔离作用,容器和容器之间独享空间和网络等


容器的基本操作

容器的基本操作包括创建(启动),停止,重启,查看,检查等,容器通过镜像创建,使用docker run命令创建,需要指定run参数,镜像名,容器执行命令,语句格式如下

docker run [OPTIONS] IMAGE [COMMAND]

在实际使用中启动一个镜像,例如

root@ubuntu:~# docker run --rm -p 5000:5000 --name container_test -d xiaogp/my_image_test:v1
6954e5372fbec11576afa8213d8810aafdc7aa2141242fc5c8cb57656327b123
(1)常用参数如下

(2)run -e覆盖Docker ENV

-e设置环境变量,格式是-e k1=v1 -e k2=v2,使得在docker镜像中的程序能够直接访问到环境变量,同时可以作为配置参数放在docker run启动镜像的时候设置,而不是写死在dockerfile在build的过程中,-e和dockerfile中的ENV变量作用相同,当变量重名时-e替换ENV,下面测试一些-e参数,在Dockerfile指定环境变量

FROM ubuntu
ENV a="12a"

直接构建成容器

root@ubuntu:~/myproject# docker build -t xiaogp/test_env .

开启一个终端启动容器内部,打印指定的环境变量a

root@ubuntu:~/myproject# docker run -it xiaogp/test_env /bin/bash
root@ubuntu:/# echo $a
12a

此时在run指令中增加-e设置环境变量,可见-e替换了Dockerfile中指定的环境变量

root@ubuntu:~/myproject# docker run -it -e a=a12 xiaogp/test_env /bin/bash
root@ubuntu:/# echo $a
a12

因为一个镜像可以启动多个容器,所以可以通过设置不同-e达到设置不同配置参数的目的,比如下一个例子在Dockerfile中设置和将环境变量写入yaml文件再供Python调用,执行的内容为打印yaml配置文件的参数内容,比如下面这个例子先看下目录结构

root@ubuntu:~/docker_test/env_test# tree
.
├── config.yml
├── Dockerfile
├── run.sh
└── test.py

其中config.yml是一个空配置文件,在run.sh中先使用echo写入追加配置参数到config.yml在执行Python脚本

#!/bin/bash
echo "host: $host" > config.yml
echo "port: $port" >> config.yml
echo "dbname: $dbname" >> config.yml

python test.py

Dockerfile中启动run.sh脚本作为容器执行命令

FROM python:3.7
ENV PIPURL=https://mirrors.aliyun.com/pypi/simple/
RUN pip install pyyaml -i ${PIPURL} --default-timeout=1000
COPY . . 
CMD ["bash", "run.sh"]

在启动容器时,使用-e指定环境变量,在run.sh中echo将环境变量拿到和写入配置文件,测试多次以不同的配置参数启动容器如下

root@ubuntu:~/docker_test/env_test# docker run -e host=192.168.60.3 -e port=3333 -e dbname=test --rm 30cd81830829
{'host': '192.168.60.3', 'port': 3333, 'dbname': 'test'}
root@ubuntu:~/docker_test/env_test# docker run -e host=192.168.60.9 -e port=3333 -e dbname=test --rm 30cd81830829
{'host': '192.168.60.9', 'port': 3333, 'dbname': 'test'}

(3)run -v覆盖Docker COPY / ADD

-v设置挂载运行,将宿主机当前目录下的文件挂载到容器中/home目录下,例如

root@ubuntu:~# docker run --rm -p 5000:5000 --name container_test -d -v `pwd`:/home xiaogp/my_image_test:v1

如果挂载的目录和Dockerfile中的COPY的目录不一致,-v会替代COPY或者ADD,例如现在Docker中COPY一个文件到容器/home目录下

FROM ubuntu
COPY . /home
WORKDIR /home
CMD ["bash", "start.sh"]

同目录下start.sh内容是打印1

#!/bin/bash
echo 1

构建镜像结束后,指定-v启动,起始挂载另外一个目录,目录下start.sh内容是打印2

#!/bin/bash
echo 2
root@ubuntu:~/docker_test# docker run -v `pwd`:/home xiaogp/volume_test 
2

(4)run command覆盖Dockerfile CMD

docker run参数中最后的COMMAND会覆盖Dockerfile中指定的CMD,例如执行echo 2替换原始Dockerfile中的CMD echo 1,输出结果是2且执行完毕后退出

# Dockerfile  echo_test
FROM ubuntu
CMD echo 1
root@ubuntu:~# docker run xiaogp/echo_test echo 2
2

(5)run --entrypoint覆盖Dockerfile ENTRYPOINT

对于Dockerfile中的ENTRYPOINT指定的启动命令docker run的COMMAND不会覆盖,如果要覆盖Docker中的ENTRYPOINT需要指定docker run中的--entrypoint参数,格式是

docker run --entrypoint [new_command] [docker_image] [optional:value]

测试一个Dockerfile输出1

# Dockerfile  echo_test:v1 
FROM ubuntu
ENTRYPOINT echo 1

在docker run中使用--entrypoint覆盖Dockerfile中的ENTRYPOINT

root@ubuntu:~/docker_test/entrypoint_test# docker run --rm --entrypoint /bin/echo xiaogp/entrypoint_test 2
2
root@ubuntu:~/docker_test/entrypoint_test# docker run --rm --entrypoint /bin/echo xiaogp/entrypoint_test 3
3

(6)其他查看容器的操作

容器启动后通过docker ps或者docker container ls查看容器,可以增加额外参数比如-a显示所有容器,默认只显示运行的容器,可以增加--no-trunc参数使得显示结果不截断,例如

root@ubuntu:~# docker ps -a --no-trunc
CONTAINER ID                                                       IMAGE                     COMMAND                                CREATED          STATUS                      PORTS     NAMES
c975fa6d0eb51e0ac739c96038cc3d7b731d8991cf98a50a6180f4a27538af84   xiaogp/my_image_test:v1   "gunicorn -c gun.conf.py manage:app"   58 seconds ago   Exited (0) 16 seconds ago             container_test

显示结果分别显示了容器的ID,镜像,执行命令,创建时间,状态,端口映射(宿主机->容器)和容器名称。对于已经运行的容器可以使用docker stop停止,如果在docker run时增加--rm参数则停止的容器保留不会自动删除,例如

root@ubuntu:~# docker stop c97
c97

除了docker stop命令还有一种停止容器的命令docker kill,相比于docker stop,docker kill是强制立即停止,而docker stop是先给了容器10秒(默认)的时间,使得容器有一定的时间处理、保存程序执行现场,优雅的退出程序,例如

root@ubuntu:~# docker kill c97
c97

在容器停止之后可以使用docker start再启动一个停止的容器,例如

root@ubuntu:~# docker start c97
c97

除此之外可以使用docker restart,此时容器可以使停止的也可以是在运行中的,例如

root@ubuntu:~# docker restart c97
c97

查看容器详情

查看容器详情使用docker inspect,比如

root@ubuntu:~/docker_test/entrypoint_test# docker inspect 3b2aa935026f
[
    {
        "Id": "3b2aa935026fa2e5d2045e42cb9f0af58152b42cb6bfc5fd81a15df150328e7f",
        "Created": "2021-06-27T01:34:11.127764986Z",
        "Path": "gunicorn",
        "Args": [
            "-c",
            "gun.conf.py",
            "manage:app"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 32559,
            "ExitCode": 0,
            "StartedAt": "2021-06-27T01:34:16.963985809Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:f9399fca099a36ecd70e9a23e20567e83a437726de641c457002c9dd96efc2c9",
        "Name": "/crazy_hamilton",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "HostConfig": {
        "Config": {
            "Hostname": "3b2aa935026f",
            "Domainname": "",
            "User": "",
            "ExposedPorts": {
                "5000/tcp": {}
            },
            "Env": [
                "PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "LANG=C.UTF-8",
                "GPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D",
                "PYTHON_VERSION=3.7.9",
                "PYTHON_PIP_VERSION=20.3.3",
                "PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/5f38681f7f5872e4032860b54e9cc11cf0374932/get-pip.py",
                "PYTHON_GET_PIP_SHA256=6a0b13826862f33c13b614a921d36253bfa1ae779c5fbf569876f3585057e9d2",
                "PIPURL=https://pypi.tuna.tsinghua.edu.cn/simple"
            ],
            "Cmd": [
                "gunicorn",
                "-c",
                "gun.conf.py",
                "manage:app"
            ],
            "Image": "xiaogp/my_image_test:v1",
            "Volumes": null,
            "WorkingDir": "/home",
            "Entrypoint": null,
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "46b1e6ae164366966b82cb70097bee4f37943e7aefb29882c954fea68680d608",
            "HairpinMode": false,
            "Ports": {
                "5000/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "5000"
                    }
                ]
            }
        }
    }
]

在以上截取的内容中展示了容器详情,包括容器id,创建时间,执行命令和参数,执行状态,容器pid,落脚点,环境变量,网络设置,端口映射等,也可以使用Go语言风格输出指定的详情,比如分别只看容器的pid和容器的执行命令

root@ubuntu:~/docker_test/entrypoint_test# docker inspect -f {{".State.Pid"}} 3b2aa935026f
32559
root@ubuntu:~/docker_test/entrypoint_test# docker inspect -f {{".Config.Cmd"}} 3b2aa935026f
[gunicorn -c gun.conf.py manage:app]

进入容器

容器是一个操作系统,可以进入这个操作系统查看容器的运行情况,有多种方式进入容器,其中主要是使用docker exec进入容器,在一个运行中的容器中执行一个命令,使用-it并带有/bin/bash命令就可以进入容器,比如

root@ubuntu:~/docker_test/entrypoint_test# docker run -p 5000:5000 -d xiaogp/my_image_test:v1
3b2aa935026fa2e5d2045e42cb9f0af58152b42cb6bfc5fd81a15df150328e7f

root@ubuntu:~/docker_test/entrypoint_test# docker ps
CONTAINER ID   IMAGE                     COMMAND                  CREATED         STATUS         PORTS                    NAMES
3b2aa935026f   xiaogp/my_image_test:v1   "gunicorn -c gun.con…"   9 seconds ago   Up 3 seconds   0.0.0.0:5000->5000/tcp   crazy_hamilton

root@ubuntu:~/docker_test/entrypoint_test# docker exec -it crazy_hamilton /bin/bash
root@3b2aa935026f:/home# ls
Dockerfile  __pycache__  blueprints  docker_run.sh  gun.conf.py   logs       models.py         run.sh       templates
PiraScore   app      data        extensions.py  gunicorn.pid  manage.py  requirements.txt  settings.py  utils.py

除了/bin/bash也可以是其他命令挂载exec后面则可以直接对一个运行中的容器执行命令,比如查看容器的进入落脚点路径,容器中的内存情况

root@ubuntu:~/docker_test/entrypoint_test# docker exec -it crazy_hamilton pwd
/home
root@ubuntu:~/docker_test/entrypoint_test# docker exec -it crazy_hamilton free
              total        used        free      shared  buff/cache   available
Mem:        7901132     2280048     3446664      411924     2174420     4913372
Swap:       2097148           0     2097148

查看容器日志

当容器以后台-d运行时,日志运行在容器内部,可以进入容器内部查看日志,也可以使用docker logs查看日志,以一个flask api接口的容器为例,日志写入文件,同时也会输出在flask的控制台

import logging
import json
import datetime
import traceback

from flask import Flask, jsonify, request
from logging.handlers import RotatingFileHandler
from logging import StreamHandler

app = Flask(__name__)
app.logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s [%(module)s] %(levelname)s %(message)s', '%Y-%m-%d %H:%M:%S')
rotating_handler = RotatingFileHandler('logs/detail.log', mode="a", maxBytes=1024 * 1024 * 100, encoding="utf8")
rotating_handler.setLevel(logging.INFO)
rotating_handler.setFormatter(formatter)
# 分别输出控制台和本地文件
app.logger.addHandler(rotating_handler)


@app.route("/search", methods=["POST"])
def api():
    try:
        data = request.get_json(force=True)
        ent = data["ent"]
        dt = data.get("dt", datetime.datetime.today().strftime("%Y-%m-%d"))
        res = {"msg": "success", "code": 200, "data": json.dumps({"ent": ent, "dt": dt}, ensure_ascii=False)}
        code = 200
    except Exception as e:
        res = {"meg": "fail", "code": 400, "trace": traceback.format_exc()}
        code = 400
    app.logger.info(res)
    return jsonify(res), code


if __name__ == '__main__':
    app.run("0.0.0.0", 5000, debug=False)

创建Dockerfile以及构建镜像,启动容器

root@ubuntu:~/docker_test/docker_logs_test# cat Dockerfile 
FROM python:3.7
MAINTAINER xiaogp
ENV PIPURL=https://mirrors.aliyun.com/pypi/simple/
RUN pip install flask -i ${PIPURL}
WORKDIR /home
COPY . .
CMD ["python", "api.py"]
root@ubuntu:~/docker_test/docker_logs_test# docker bulid -t xiaogp/docker_logs .
root@ubuntu:~/docker_test/docker_logs_test# docker run -p 5000:5000 -d xiaogp/docker_logs

启动一个脚本不断请求api接口

import time
import uuid
import requests

while True:
    res = requests.post("http://127.0.0.1:5000/search", json={"ent": uuid.uuid4().hex})
    time.sleep(3)

进入容器内部查看日志

root@ubuntu:~/docker_test/docker_logs_test# docker exec -it d8020c4f99bb /bin/bash
root@d8020c4f99bb:/home# ls
Dockerfile  api.py  logs
root@d8020c4f99bb:/home# cd logs/
root@d8020c4f99bb:/home/logs# ls
detail.log
root@d8020c4f99bb:/home/logs# more detail.log 
2021-06-29 07:55:56 [api] INFO {'msg': 'success', 'code': 200, 'data': '{"ent": "8761c66441d24a2a910be856e68298d4", "dt": "2021-06-29"}'}
2021-06-29 07:55:59 [api] INFO {'msg': 'success', 'code': 200, 'data': '{"ent": "18bf77d79b10492b9406c56263247c5b", "dt": "2021-06-29"}'}
2021-06-29 07:56:02 [api] INFO {'msg': 'success', 'code': 200, 'data': '{"ent": "68188ba02154436fa861cd11f5027699", "dt": "2021-06-29"}'}
root@d8020c4f99bb:/home/logs# 

另一种方式是直接使用docker logs命令,比如使用-f追踪输出,并且从最后的第1行开始输出

root@ubuntu:~/docker_test/docker_logs_test# docker logs -f -n 1 d8020c4f99bb
172.17.0.1 - - [29/Jun/2021 08:01:13] "POST /search HTTP/1.1" 200 -
[2021-06-29 08:01:16,190] INFO in api: {'msg': 'success', 'code': 200, 'data': '{"ent": "8c3851e0c3ca4c0fbb7dbd245f8deb0f", "dt": "2021-06-29"}'}
172.17.0.1 - - [29/Jun/2021 08:01:16] "POST /search HTTP/1.1" 200 -
[2021-06-29 08:01:19,204] INFO in api: {'msg': 'success', 'code': 200, 'data': '{"ent": "39d775d3a32c4cd19f9f1a836a377ece", "dt": "2021-06-29"}'}
172.17.0.1 - - [29/Jun/2021 08:01:19] "POST /search HTTP/1.1" 200 -

此时宿主机的logs目录下为空,容器中的logs目录下存在detail.log文件,如果使用-v将宿主机目录挂载到容器作为容器写入的目录,则容器中数据的变动会同步到本地,这样可以直接在本地查看日志,修改容器启动为-v挂载的形式

root@ubuntu:~/docker_test/docker_logs_test# docker run -p 5000:5000 -d -v `pwd`:/home xiaogp/docker_logs

此时本地logs目录下开始产生日志,且这个日志和容器内的logs目录下一致

root@ubuntu:~/docker_test/docker_logs_test/logs# cat detail.log 
2021-06-29 08:07:36 [api] INFO {'msg': 'success', 'code': 200, 'data': '{"ent": "2dd127e80a6246ee8e106961147bfee6", "dt": "2021-06-29"}'}
2021-06-29 08:07:39 [api] INFO {'msg': 'success', 'code': 200, 'data': '{"ent": "666d348b7635417eb55f2771ab33c248", "dt": "2021-06-29"}'}
2021-06-29 08:07:42 [api] INFO {'msg': 'success', 'code': 200, 'data': '{"ent": "76ec19a0fc1a4e12ba82292f3fc087e4", "dt": "2021-06-29"}'}
2021-06-29 08:07:45 [api] INFO {'msg': 'success', 'code': 200, 'data': '{"ent": "f9eb6bd15a50431e9771c2257b486a16", "dt": "2021-06-29"}'}
2021-06-29 08:07:48 [api] INFO {'msg': 'success', 'code': 200, 'data': '{"ent": "59c66d8688574991a3cae021c646bba5", "dt": "2021-06-29"}'}

容器修改生成镜像

如果容器内的内容改变了,此时删除容器从镜像重新启动容器则改动的内容将不会存在,如果相对修改过的容器保留下来则可以从容器生成新的镜像,先测试以下容器内修改在删除的容器后将不再生效,在已有容器中使用pip安装Python包

root@ubuntu:~/docker_test/entrypoint_test# docker exec -it 3b2aa935026f /bin/bash

root@3b2aa935026f:/home# pip install pymongo -i $PIPURL
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting pymongo
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/b1/29/c0c8791ba972456f8aa3f027af33206499bc9f52a948e0d9c10909339b3c/pymongo-3.11.4-cp37-cp37m-manylinux2014_x86_64.whl (512 kB)
     |████████████████████████████████| 512 kB 7.6 MB/s 
Installing collected packages: pymongo
Successfully installed pymongo-3.11.4

此时退出容器,并且删除容器,最后从镜像重新生成容器

root@3b2aa935026f:/home# exit
root@ubuntu:~/docker_test/entrypoint_test# docker rm -f 3b2
3b2
root@ubuntu:~/docker_test/entrypoint_test# docker run -d -p 5000:5000 xiaogp/my_image_test:v1

此时进入容器检查,并不存在pymongo包

root@ubuntu:~# docker exec -it c8b /bin/bash
root@c8bcc65a8513:/home# pip list|grep pymongo
root@c8bcc65a8513:/home# 

如果要容器变化保存下来需要以这个新容器生成一个镜像,使用docker commit,语法如下

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

以新安装pymongo的容器为例,对新容器使用docker commmit

root@ubuntu:~# docker exec -it c8bcc65a8513 /bin/bash
root@c8bcc65a8513:/home# pip install pymongo -i $PIPURL
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting pymongo
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/b1/29/c0c8791ba972456f8aa3f027af33206499bc9f52a948e0d9c10909339b3c/pymongo-3.11.4-cp37-cp37m-manylinux2014_x86_64.whl (512 kB)
     |████████████████████████████████| 512 kB 4.3 MB/s 
Installing collected packages: pymongo
Successfully installed pymongo-3.11.4
root@c8bcc65a8513:/home# exit
exit
root@ubuntu:~#

新生成的镜像叫做xiaogp/my_image_test:v2

root@ubuntu:~# docker commit -m="pip install pymongo" -a="xiaogp" c8bcc65a8513 xiaogp/my_image_test:v2
sha256:094ab012ea3fc41865ce75647405fd3a5ecc441a267511c7fa12c74a226ad0aa

从新镜像启动容器并进入容器查看存在新安装的pymongo

oot@ubuntu:~# docker exec -it a3f434b153fa /bin/bash
root@a3f434b153fa:/home# pip list|grep pymongo
pymongo            3.11.4
root@a3f434b153fa:/home# 

上一篇下一篇

猜你喜欢

热点阅读