Release time:2020-09-30 16:28:42 Views:18482
be familiar withDockerAll of our friends know,DockerYes, remote control can be enabledAPIof,Default listeningTCP 2375port,It has very rich interface methods,Can be used for remote controlDocker DaemonTo do many operations。DockerVersion iteration is fast,Therefore, different versions ofAPIfile,This article is mainly based on the latestv1.40Briefly introduce some common operations and best practices。
Centos The system can be used directlyyumCommand online installation,For details, please refer toOfficial documents,One is provided belowLinuxGeneral online installation method of the system:
curl -sSL https://get.docker.com | sh
curl -sSL https://get.daocloud.io/docker | sh
For more system installation methods, refer toDocuments collated by predecessors,After successful installation,Executable docker info、docker version、docker ps Wait for the command to test whether it is normal,The specific process will not be repeated。
If it is a domestic host,In order to make the following practice more smooth,You can configure it hereDaoCloudProvidedDockerImage acceleration,Perform the following2Command:
# Configuration accelerationcurl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io# restartDockersystemctl restart docker
To ensure safety,DockerRemote will not be enabled by default after installationAPIservice,Because this service does not perform permission authentication by default。This article is mainly about practice sharing,It is also used in intranet production environment,Security will be guaranteed,If it is an external network production environment, it is recommended to do a good jobiptablesSecure or burn or use immediately after useTLSSecurity certification,Not shown here。
The opening method is relatively simple,Only share hereCentOS 7Steps to enable the system:
vi /lib/systemd/system/docker.service
findExecStartConfiguration Item,The default is as follows:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Insert listening option:-H tcp://0.0.0.0:2375(If it is an intranet production environment,Please set0.0.0.0Change to intranetIP),Finally:
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock
systemctl daemon-reloadsystemctl restart docker
[root@centos ~]# netstat -nutlp | grep 2375tcp6 0 0 :::2375 :::* LISTEN 3586/dockerd
[root@centos ~]# docker versionClient: Docker Engine - CommunityVersion: 19.03.2API version: 1.40 # NativeDockerVersion as clientGo version: go1.12.8Git commit: 6a30dfcBuilt: Thu Aug 29 05:28:55 2019OS/Arch: linux/amd64Experimental: falseServer: Docker Engine - CommunityEngine:Version: 19.03.2API version: 1.40 (minimum version 1.12) # NativeDockerAs the server versionGo version: go1.12.8Git commit: 6a30dfcBuilt: Thu Aug 29 05:27:34 2019OS/Arch: linux/amd64Experimental: falsecontainerd:Version: 1.2.6GitCommit: 894b81a4b802e4eb2a91d1ce216b8817763c29fbrunc:Version: 1.0.0-rc8GitCommit: 425e105d5a03fabd737a126ad93d62a9eeede87fdocker-init:Version: 0.18.0GitCommit: fec3683
After completing the above steps,DockerIt already supports remote control,Let's refer toOfficial documentsTry to pull up an image(The following operations are completed locally,thereforeIPAll127.0.0.1):
curl -XPOST "http://127.0.0.1:2375/v1.40/images/create?fromImage=centos&tag=latest"
curl -H "Content-Type: application/json" http://127.0.0.1:2375/containers/create?name=demo1 -d '{"Image": "centos:latest","HostConfig": {"NetworkMode": "host","Binds": ["/tmp:/tmp"]},"Cmd": ["tail","-f","/dev/null"]}'
The following is returned successfully:
{"Id":"b88c7c986ecd5fdf174f79b00e024087b47241cd40653bcb05df70fba5cc398f","Warnings":[]}
# You can use theidTo start:curl -XPOST http://127.0.0.1:2375/containers/b88c7c986ecd5fdf174f79b00e024087b47241cd40653bcb05df70fba5cc398f/start# You can also use the container name defined in the previous stepdemo1To start:curl -XPOST http://127.0.0.1:2375/demo1/start
[root@centos ~]# docker ps | grep demo1ed9f2150f8d5 centos:latest "tail -f /dev/null" About a minute ago Up About a minute demo1
callAPI,For existing containersdemo1Create Command Instance:
curl -H "Content-Type: application/json" http://127.0.0.1:2375/containers/demo1/exec -d '{ "AttachStdin": false,"AttachStdout": true,"AttachStderr": true,"DetachKeys": "ctrl-p,ctrl-q","Tty": false,"Cmd": ["sh","-c","date | tee /tmp/test_exec.log"],"Env": ["FOO=bar","BAZ=quux"]}'
The returned result is a command instanceId:
{"Id":"08552937782f6c5b696454d5524b140337fb0652d5f39142ac57ceaf46732bb4"}
Continue callingAPIStart this command instance:
curl -XPOST -H "Content-Type: application/json" http://127.0.0.1:2375/exec/08552937782f6c5b696454d5524b140337fb0652d5f39142ac57ceaf46732bb4/start -d '{ "Detach": false,"Tty": false}'Fri Oct 4 03:21:36 UTC 2019
As above, adateEcho of commands,And will be mounted at/tmpDirectory Generationtest_exec.logtext,The content is consistent with the echo in the previous step:
[root@centos ~]# cat /tmp/test_exec.log Fri Oct 4 03:21:36 UTC 2019
Indicates that the command was successfully executed!
The above steps,Simple demonstrationDocker APICommon scenarios for,so to speakDocker APIGreatly simplifies the operation and maintenance work,As we often sayCI/CDCan no longer rely onsshChannel or self builtagentHas,One interface can handle the whole life cycle of the application,It is the savior of operation and maintenance!
Ps:moreDocker APIYou can refer to the usage ofOfficial documents。
DockerIs so popular,It's definitely necessary for each languageSDK,The most commonly used high-level language for O&M isPython,So here's a brief introductionDockerofPython SDK,And usePythonofSDKTo achieve the aboveAPITedious operation of:
# withoutpip,Install firstpip:yum install python-pippip install --upgrade pip# installSDKpip install docker
# -- coding: utf8 --import docker# initialization,Here, according to the targetdockerVersion executionAPIedition,If an error is reported later, you need to adjust the same version or lower version of the target hereclient = docker.DockerClient(version='1.40', base_url='tcp://127.0.0.1:2375')# Pull Imageclient.images.pull('centos:latest')# Pull up the containerclient.containers.run(image='centos:latest', name='demo1', command='tail -f /dev/null',volumes={'/data': {'bind': '/tmp', 'mode': 'rw'}}, detach=True)# Get the object by container name firstcontainer = client.containers.get('demo1')# Executing commands through objectsresult = container.exec_run(cmd='sh -c "date | tee /tmp/test_sdk.log"', detach=False, tty=True, stdin=True, stdout=True)# Output the return code and result of executing the commandprint(result.exit_code)print(result.output.decode())
The above code is saved as test_sdk.py,implement python test_sdk.py View results later:
[root@centos ~]# python test_sdk.py 0Sun Oct 6 01:48:58 UTC 2019[root@centos ~]# cat /data/test_sdk.log Fri Oct 4 03:35:14 UTC 2019
adoptSDKOperation demonstration of,It is obvious that the operation steps are greatly simplified,The overall process becomes more smooth!
Ps:More play methods can be referred toOfficial documents。
The above practice proves that,YesDocker Remote APIThis sharp tool for operation and maintenance(passageway),Many traditional operation and maintenance methods can be innovated,Here's a brief introduction,How we useDocker Remote APITo implementHaoproxyRemote management of(All codes and images have been uploaded toGitHubandDockerHub)。
first,We build aHaporxyConfigure centralized management service,Used for interface managementHaproxyto configure,It also provides an interface to pull the specified configuration content,such as:
curl -s --max-time 120 --retry 3 -w %{http_code} -o 192.168.1.100.cfg http://192.168.1.1/haproxy/192.168.1.100
then,stayHaproxyOne integrated in the imageshellscript,For pulling、comparison、to updateHaproxyProfile for。
last,Remote callDocker Remote API implementHaproxyInside the containershellScript UpdateHaproxyto configure,If the update is successful, continue to callDocker API heavy loadHaproxyto configure,That's itHaproxyConfigured Smooth Updates。
To quickly demonstrate the effect,Directly used hereNginxDeploy aHaproxyConfigured download service,A more perfect management platform must be built for actual use。
# installNginxyum install -y nginx# start-upNginx/sbin/nginx# Create a minimalisthaproxyconfiguration filecat > /usr/share/nginx/html/127.0.0.1 <<EOFglobalnbproc 1pidfile /usr/local/haproxy/logs/127.0.0.1.piddefaultstimeout connect 300stimeout client 300stimeout server 300slisten admin_statbind 0.0.0.0:8080mode httpstats refresh 60sstats uri /haproxystats auth admin:123456stats admin if TRUE################################################## status end ###############################################EOF# Request Test,The above is successcurl http://127.0.0.1/127.0.0.1
It is directly based on the official image,Additional integration for updatingHaproxyConfigured scripts and some common commands(curl、vim、ps):
DockerfileThe contents are as follows:
FROM haproxy:latestRUN apt-get update \&& apt-get install -y curl vim procps \&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=falseCOPY update_cfg.sh /opt/COPY docker-entrypoint.sh /CMD ["haproxy","-f","/etc/haproxy.cfg"]
update_cfg.sh For download、comparison、to updateHaproxyto configure,grammar、The logic is quite simple,You can have a look if you are interested:
#!/bin/bashsource /etc/profileif [ -z $VIP ];thenecho 'ENV ${VIP} is not SET, Plz check!'exit 1fi# Define and create storage directoryetc_dir=${STORAGE_DIR:-/usr/local/haproxy/etc}temp_dir=${etc_dir}/tempback_dir=${etc_dir}/backupmkdir -p ${back_dir} ${temp_dir}# Define the configration filecurrent_cfg=${etc_dir}/${VIP}.cfgbackup_cfg=${back_dir}/${VIP}_$(date +%F-%H%M%S).cfgtemp_cfg=${temp_dir}/${VIP}.cfg# Define file download configrationcurl_bin=$(which curl)cfg_manage_api=${CFG_GET_URL:-http://your_haporxy_download_svr/haproxy/}${VIP} # You need to modify the address according to the actual situation of the configuration management service# console logreport_log(){echo "[$(date '+%F %H:%M:%S')] $*"}# backup current configration filebackup_cfg(){if [ -f ${current_cfg} ];thencp -a ${current_cfg} ${backup_cfg} && \report_log "Backup ${current_cfg} to ${backup_cfg} success." || \report_log "Backup ${current_cfg} to ${backup_cfg} failed."elsereport_log "${current_cfg} is not exist, maybe the first release, skiped."fi}# update current configration filecover_cfg(){ if [ -f ${temp_cfg} ];thencp -a ${temp_cfg} ${current_cfg} && \report_log "Cover ${temp_cfg} to ${current_cfg} success." || (report_log "Cover ${temp_cfg} to ${current_cfg} failed."exit 1)elsereport_log "${temp_cfg} is not exist, Unknow Error, exited."exit 1fi}# download latest configration file from download svrdownload_cfg(){report_log "Starting Download configration file to ${temp_cfg} ..."ret_code=$(${curl_bin} -s --max-time 120 --retry 3 -w %{http_code} -o ${temp_cfg} ${cfg_manage_api})if [ $ret_code -eq 200 ] && [ $? -eq 0 ];thenreport_log "Download configration file ${temp_cfg} success."elsereport_log "Download configration file ${temp_cfg} failed."exit 1fi}# check the latest configration check_cfg(){old_md5=$(test -f ${current_cfg} && md5sum ${current_cfg} | awk '{print $1}' 2>/dev/null )new_md5=$(md5sum ${temp_cfg}|awk '{print $1}')if [ "$old_md5" = "$new_md5" ];thenreport_log "The configuration file ${VIP}.cfg is the same, no need update."return 2fiif haproxy -c -W -f ${temp_cfg} >/dev/null ;thenreport_log "Configuration file ${temp_cfg} is valid."return 0elsereport_log "Configuration file ${temp_cfg} is invalid."return 1fi}download_cfgif check_cfg;thenbackup_cfgcover_cfg && \report_log "${current_cfg} is updated success!"elseexit $?fi
docker-entrypoint.sh Modified fromHaproxyOfficial image,Added a pair ofVIPJudgment of environmental variables、Update download of configuration file、Soft link establishment of configuration file、Configure logic such as syntax check:
#!/bin/sh# first arg is `-f` or `--some-option`if [ "${1#-}" != "$1" ]; thenset -- haproxy "$@"fiif [ "$1" = 'haproxy' ]; thenif [ -z $VIP ];thenecho echo "[$(date '+%F %H:%M:%S')] ENV \${VIP} is not SET, Plz check!"exit 1fibash /opt/update_cfg.shln -sf /usr/local/haproxy/etc/${VIP}.cfg /etc/haproxy.cfghaproxy -W -c -f /etc/haproxy.cfg || (echo "[$(date '+%F %H:%M:%S')] Haproxy Configuration file check failed, Plz check!"exit 1)shift # "haproxy"# if the user wants "haproxy", let's add a couple useful flags# -W -- "master-worker mode" (similar to the old "haproxy-systemd-wrapper"; allows for reload via "SIGUSR2")# -db -- disables background modeset -- haproxy -W -db "$@"fiexec "$@"
After preparing the above documents,Execute the following command in the file peer directory to buildHaproxyimage(In fact, this step can also be achieved throughAPITo operate,I won't repeat it here,SeeOfficial documents):
# Script gives execution permission:chmod +x *.sh# If there is a private warehouse, it can be downloaded to the private warehouse,This article is mainly about sharing,Build directly and locally here:docker build -t "haproxy-plus:latest" ./
To fit the theme of the article,So continue to useDocker APIPull up the container remotely:
# -- coding: utf8 --import dockerclient = docker.DockerClient(version='1.40', base_url='tcp://127.0.0.1:2375')#client.images.pull('haproxy-plus:latest') # Local test,So there is no need to pull the imageclient.containers.run(image='haproxy-plus:latest', name='demo2', volumes={'/data/images/haproxy/etc': {'bind': '/usr/local/haproxy/etc', 'mode': 'rw'}}, network_mode='host', environment=["VIP=127.0.0.1", "CFG_GET_URL=http://127.0.0.1/"], detach=True)
Several key settings:
Mount the local directory /data/images/haproxy/etc To container /usr/local/haproxy/etc catalogue,Used for persistent configuration;
environment variable VIP,Used to specifyhaproxyConfiguration name for(On our side, it isVIPaddress),It is also used to pull the specified configuration through the interface;
environment variable CFG_GET_URL,PullHaproxyConfigured address,combinationVIPLater http://127.0.0.1/127.0.01,The temporary download address above
abovePythonSave Code Asstart.py,The execution results are as follows:
[root@centos haproxy]# python start.py [root@centos haproxy]# docker logs -f demo2 # View Execution Log[2019-10-04 04:32:10] Starting Download configration file to /usr/local/haproxy/etc/temp/127.0.0.1.cfg ...[2019-10-04 04:32:10] Download configration file /usr/local/haproxy/etc/temp/127.0.0.1.cfg success.[2019-10-04 04:32:10] Configuration file /usr/local/haproxy/etc/temp/127.0.0.1.cfg is valid.[2019-10-04 04:32:10] /usr/local/haproxy/etc/127.0.0.1.cfg is not exist, maybe the first release, skiped.[2019-10-04 04:32:10] Cover /usr/local/haproxy/etc/temp/127.0.0.1.cfg to /usr/local/haproxy/etc/127.0.0.1.cfg success.[2019-10-04 04:32:10] /usr/local/haproxy/etc/127.0.0.1.cfg is updated success!Configuration file is valid[NOTICE] 276/043210 (1) : New worker #1 (27) forked
adoptDockerLog of,The startup process is analyzed as follows:
Download via interfaceHaproxyto configure,Save as /usr/local/haporxy/etc/temp/127.0.0.1.cfg;
implementHaproxyConfigure syntax validation:haproxy -c -W /usr/local/haproxy/etc/temp/127.0.0.1.cfg;
After successful syntax verification,adoptMD5Value to compare whether the configuration is updated,Found that the original configuration could not be found,Description is the first start;
Copy temporary configuration file to formal configuration file:/usr/local/haproxy/etc/127.0.0.1.cfg
start-upHaproxysuccess:New worker #1 (27) forked
here,Access ConfigurationhaproxyStatus Page http://<IP>:8080/haproxy,Enter the account password:admin/123456 Look at the effect:
Results meet expectations,Let's try to update the configuration,The update script is written as follows,yesDocker APIofSDKA little encapsulation:
# -- coding: utf8 --import dockerclass dockerApi():def __init__(self,ip,port=2375):self.base_url = 'tcp://%s:%s' % (ip,port)self.client = docker.DockerClient(version='1.40', base_url=self.base_url)def exec_cmd(self,container_name, cmd='echo ok',decode=True):container = self.client.containers.get(container_name)result = container.exec_run(cmd=cmd, detach=False, tty=True, stdin=True, stdout=True)ret_code = result.exit_codeif decode:ret_info = result.output.decode()else:ret_info = result.outputreturn ret_code, ret_infodef send_kill(self, container_name):container = self.client.containers.get(container_name)container.kill('SIGUSR2')# definitionhaproxyHostIP,It can be multipleld_list = ['127.0.0.1']# Define commands for updating configurationscmd = 'bash /opt/update_cfg.sh'# Define Container Namecontainer_name = 'demo2' # Start Updatefor i in ld_list:obj = dockerApi(i)ret_code,ret_info = obj.exec_cmd(container_name, cmd)print '%s exec %s ret_code is: %s, exec ret_info:' % (i, cmd, ret_code)print ret_infoif int(ret_code) == 0:obj.send_kill(container_name)
Save as update.py,The execution results are as follows:
[root@centos haproxy]# python update.py 127.0.0.1 exec bash /opt/update_cfg.sh ret_code is: 2, exec ret_info:[2019-10-04 04:55:41] Starting Download configration file to /usr/local/haproxy/etc/temp/127.0.0.1.cfg ...[2019-10-04 04:55:41] Download configration file /usr/local/haproxy/etc/temp/127.0.0.1.cfg success.[2019-10-04 04:55:41] The configuration file 127.0.0.1.cfg is the same, no need update.
Log prompt is,The configuration has not changed,So there is no need to upgrade,Meets expectations。below,We modify the central configuration,Set the listening port from8080Change to8181:
cat > /usr/share/nginx/html/127.0.0.1 <<EOFglobalnbproc 1pidfile /usr/local/haproxy/logs/127.0.0.1.piddefaultstimeout connect 300stimeout client 300stimeout server 300slisten admin_stat_8181bind 0.0.0.0:8181mode httpstats refresh 60sstats uri /haproxystats auth admin:123456stats admin if TRUE################################################## status end ###############################################EOF# Request Test,The above is successcurl http://127.0.0.1/127.0.0.1
The results of re execution are as follows:
[root@centos haproxy]# python update.py 127.0.0.1 exec bash /opt/update_cfg.sh ret_code is: 0, exec ret_info:[2019-10-04 05:03:43] Starting Download configration file to /usr/local/haproxy/etc/temp/127.0.0.1.cfg ...[2019-10-04 05:03:43] Download configration file /usr/local/haproxy/etc/temp/127.0.0.1.cfg success.[2019-10-04 05:03:43] Configuration file /usr/local/haproxy/etc/temp/127.0.0.1.cfg is valid.[2019-10-04 05:03:43] Backup /usr/local/haproxy/etc/127.0.0.1.cfg to /usr/local/haproxy/etc/backup/127.0.0.1_2019-10-04-050343.cfg success.[2019-10-04 05:03:43] Cover /usr/local/haproxy/etc/temp/127.0.0.1.cfg to /usr/local/haproxy/etc/127.0.0.1.cfg success.[2019-10-04 05:03:43] /usr/local/haproxy/etc/127.0.0.1.cfg is updated success!
Compared to the first startup log,The process of updating the configuration is as follows:
Download via interfaceHaproxyto configure,Save as /usr/local/haporxy/etc/temp/127.0.0.1.cfg;
implementHaproxyConfigure syntax validation:haproxy -c -W /usr/local/haproxy/etc/temp/127.0.0.1.cfg;
After successful syntax verification,adoptMD5Value to compare whether the configuration is updated,If there is an update,Back up the original configuration file to /usr/local/haproxy/etc/backup/127.0.0.1_2019-10-04-050343.cfg;
Copy temporary configuration file to formal configuration file:/usr/local/haproxy/etc/127.0.0.1.cfg
Because of theupdate_cfg.shScript only updates configuration files,thereforePythonThe last step of the script will also verify the script return code,If it meets the expectation, akillinstructions,Smooth overloadHaproxy,It is mainly used hereHaproxyof-Wparameter,Official interpretationas follows:
If you used a bind mount for the config and have edited your haproxy.cfg file, you can use HAProxy's graceful reload feature by sending a SIGHUP to the container:
$ docker kill -s HUP my-running-haproxy
The entrypoint script in the image checks for running the command haproxy and replaces it with haproxy-systemd-wrapper from HAProxy upstream which takes care of signal handling to do the graceful reload. Under the hood this uses the -sf option of haproxy so "there are two small windows of a few milliseconds each where it is possible that a few connection failures will be noticed during high loads" (see Stopping and restarting HAProxy). Image Variants
Continue to view the container's log,We can see that there are2Segment Log,The first section is the first startup,The second paragraph is after the configuration is updated,send outkillinstructions,HaproxyOverloaded Log:
[root@centos haproxy]# docker logs -f demo2[2019-10-04 05:03:19] Starting Download configration file to /usr/local/haproxy/etc/temp/127.0.0.1.cfg ...[2019-10-04 05:03:20] Download configration file /usr/local/haproxy/etc/temp/127.0.0.1.cfg success.[2019-10-04 05:03:20] Configuration file /usr/local/haproxy/etc/temp/127.0.0.1.cfg is valid.[2019-10-04 05:03:20] /usr/local/haproxy/etc/127.0.0.1.cfg is not exist, maybe the first release, skiped.[2019-10-04 05:03:20] Cover /usr/local/haproxy/etc/temp/127.0.0.1.cfg to /usr/local/haproxy/etc/127.0.0.1.cfg success.[2019-10-04 05:03:20] /usr/local/haproxy/etc/127.0.0.1.cfg is updated success!Configuration file is valid[NOTICE] 276/050320 (1) : New worker #1 (27) forked[WARNING] 276/050343 (1) : Reexecuting Master process[NOTICE] 276/050343 (1) : New worker #1 (53) forked[WARNING] 276/050343 (27) : Stopping proxy admin_stat in 0 ms.[WARNING] 276/050343 (27) : Stopping frontend GLOBAL in 0 ms.[WARNING] 276/050343 (27) : Proxy admin_stat stopped (FE: 0 conns, BE: 0 conns).[WARNING] 276/050343 (27) : Proxy GLOBAL stopped (FE: 0 conns, BE: 0 conns).[WARNING] 276/050343 (1) : Former worker #1 (27) exited with code 0 (Exit)
last,Visit againHaporxyStatus page for http://<IP>:8181/haproxy Validation effect,Port successfully updated to8181,Meets expectations:
Update configuration above、The process of heavy loading has been measured by me,Confirm it is smooth and undamaged。In production environment,We only need centralized management on the operation and maintenance platformHaproxyConfiguration of,ThroughDockerofAPITo controlHaproxySecond level configuration update!Is it quite awesome?
By the way, here's a good news:Haproxyabreast of the times2.0SupportedDataplaneapiTo remotely manage the configuration,You can have a look if you are interestedOfficial documents。
But because of the burden of history,If we want to cut toDataplaneapiOur management mode requires more development resources,So give up,Continue the above shared management plan temporarily,After sufficient manpower, considerDataplaneapiMore detailed management mode of。
This article starts fromDockerinstall、Docker Remote APIas well asPython SDKUse of,More detailed displayDocker Remote APICommon Scenarios for,Finally, based onDocker Remote APIShared a quick landingHaproxyRemote Management Best Practices,Hope to be helpful to friends in need。
Things go around the world
Multi warehouse direct delivery Fast delivery, multi warehouse direct delivery Extreme speed matching
Exquisite service
Exquisite service After sales guarantee and refined service After sales guarantee
Return and exchange worry free
Shopping with confidence Return to worry free shopping Return without worry
Full reduction activity
full500Yuan Lijian90,New user reduction200
Open WeChat,Click on the bottom“find”
use“scan”You can share the webpage to your friends