Инструменты пользователя

Инструменты сайта


linux:containers

Контейнеры в Linux

Docker

Установка docker

:!: Установка docker
# apt install docker docker.io && systemctl enable docker
 
# Установка на CentOS/Alma вместе с compose 
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
 
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
 
curl -L "https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-linux-x86_64" -o /usr/bin/docker-compose
chmod +x /usr/bin/docker-compose && docker-compose --version
  # Скачать образ из репозитория:
docker pull wallarm/node
 
  # Загрузить образ в репозиторий:
docker push example.com:5000/my_image
 
  # Запустить свой registry можно всего одной командой:
docker run -d -p 5000:5000 --restart=always --name registry registry:2

Работа с контейнерами

:!: Команды
  • system - системная информация
    • df - занимаемое место на диске
    • prune - очистить неиспользуемые данные
    • events, info
  • images - перечень локальных образов
  • ps [-a] || container ls - перечень работающих [всех] контейнеров
  • top - процессы внутри контейнера
  • logs - логи контейнера
  • stop - «лояльная» остановка (остановить все можно так: docker stop $(docker container ls -q))
  • kill - жесткая остановка
  • rm - удалить контейнер
  • rmi - удаление образа (с указанием имени и версии образа)
  • pull - скачивание образа из репозитория (актуальную версию, сравнивает контрольную сумму)
  • search - поиск образов в репозитории
  • run - запуск образа (создание контейнера)
    • -i - интерактивный режим
    • -t - поддержка эмулятора
    • -d - фоновый режим (отсоединенный)
    • –name - указание имени для создаваемого контейнера
    • -
  • start - запуск контейнера (уже созданного)
  • exec - доступ к работающему контейнеру
  • ctrl+ q - отсоединиться от работающего контейнера
  • attach - присоединиться к работающему контейнеру
:!: Инструкции Dockerfile

Комментарии в файле с помощью #

FROM Обязательно, первая инструкция. Какой базовый образ нужно использовать FROM ubuntu:16.04
RUN Создает новый слой и выполняет команду. Родственная с CMD и ENTRYPOINT, во всех трех принимается как shell скрипт так и json синтаксис (в квадратных скобках) RUN apt-get install python или RUN [«mkdir», «/my_dir»]
CMD Запускает команду с аргументами, каждый раз при запуске контейнера. Если указано несколько, то будет выполнена последняя CMD [«openvpn»]
ENTRYPOINT Похожа на CMD, но ее пар-ры не переопределяются а добавляются из строки запуска контейнера ENTRYPOINT [«/sbin/apache2»]
WORKDIR Рабочая директория для команд ENTRYPOINT,RUN,COPY,ADD (CMD ?) WORKDIR /opt/apps
COPY Копирует файлы и деректории из рабочей папки в контейнер, создаст все пути COPY ./mypassw/ /root/
ADD Тоже самое но распакует архив либо скачает с URL, не рекоммендуется без необходимости этих ф-й ADD https://site/video.mp4 /my_dir/
VOLUME Добавляет том в контейнер для хранения постоянных данных VOLUME [«/opt/myapp»]
USER Задает пользователя, от которого будет запущен образ USER user:group
ENV Задает переменные окружения в образе ENV PGPASSWD pass
ARG Создает переменную, которая доступна сборщику (в т.ч. в этом же файле). Фича - можно использовать для переопределения при билде образов ARG folder=/opt/apps WORKDIR $folder
EXPOSE Указывает какой порт нужно пробросить из контейнера. Фактически не пробрасывает ничего, это форма документации для запускающего, для маппинга нужен аргумент -p при запуске (хост:конт). Хотя вроде используется в контейнерной сети, там доступен другим контейнерам EXPOSE 80
MAINTAINER Автор образа MAINTAINER eNod
LABEL Добавляет информацию LABEL version=«2»
SHELL Позволяет заменить оболочку для выполнения команд на пользовательскую SHELL [«/bin/sh», «-c»]
HEALTHCHECK Команда которая будет проверять работоспособность контейнера HEALTHCHECK –interval=5m –timeout=3s CMD curl -f http://localhost ll (верт черта) exit 1
ONBUILD Действия, которые выполняются, если наш образ используется как базовый для другой сборки ONBUILD ADD ./app/src
STOPSIGNAL Переопределяет сигнал SIGTERM для завершения контейнера STOPSIGNAL SIGINT

Примечания:
CMD:

  • Может включать исполняемый файл;
  • Если не содержит никакого файла, обязательно должна быть ENTRYPOINT, в таком случае обе должны быть в формате JSON;
  • Аргументы при запуске docker-образа переопределяют аргументы в CMD;
  • По ходу сборки не фиксирует никакого результата;
  • Полезен когда нужно переопределять аргументы из строки запуска;

ENTRYPOINT:

  • Dockerfile должен содержать либо CMD либо ENTRYPOINT;
  • Нужен когда нужно запустить одну и туже команду несколько раз;
  • «Используйте когда ваш контейнер выступает в роли исполняющейся программы» (?);

Установка пакетов:

  • В Alpine образах есть какой то менеджер apk;
  • Можно использовать файл «requirements.txt» с перечислением необходимых пакетов;

WORKDIR:

  • Создаст отсутствующие директории;
  • Можно использовать несколько инструкций;
  • Правило хорошего тона юзать абсолютные пути;

ARG:

  • Значения не доступны в работающем контейнере, но можно использовать как дефолт на случай если не переопределили при билде, это фича, при запуске передаем нужное значение в «–build-arg»;
  • пример: ARG folder=/opt/apps WORKDIR $folder; docker build .. –build-arg folder=/my_fold
:!: Работа в консоли

Экспорт/Импорт вольюма:

  # *container-name - имя контейнера к которому привязан вольюм; 
  # *volume-path - путь монтирования вольюма внутри контейнера;
  # После команды, docker запустит контейнер и создаст архив с содержимым
docker run --rm --volumes-from container-name -v $(pwd):/backup ubuntu bash -c "cd /volume-path && tar zcf /backup/backup.tar.gz ."
 
# Для восстановления
docker run --rm --volumes-from container-name -v $(pwd):/backup ubuntu bash -c "cd /volume-path && tar zxf /backup/backup.tar.gz"

Еще команды. Работа с образами и контейнерами

  # -q возвращает только ID объектов
docker rmi $(docker images -q)
docker rm $(docker ps --filter status=exited -q)
 
  # Остановить все действующие контейнеры
docker stop $(docker ps -a -q)
docker stop $(docker ps -q --filter name=^web)
 
  # Принудительно удалить образы
docker rmi -f <имя или ID>

Примеры

:!: Работа с контейнерами
  # Возобновить (уже созданный, остановленный) контейнер
docker start [id]
  # Подключится к работающему контейнеру (после этого сложно отключится, вроде как ctrl+p ctrl+q но нифига не рабоатет, т.ч. лучше запускать шелл)
docker attach [id]
 
  # Подключится и запустить доп процесс
docker exec -it [id] bash
 
  # Работающие контейнеры
docker ps [-a]
 
docker image [list prune (-a) inspect]
 
docker container [list prune (-a) inspect]
 
 
  # Процессы
docker top <name>
  # Ресурсы
docker stats <name>
  # Порты
docker port <name>
  # Проброс папок при запуске
docker run -it -v /AbsoluteExistPath:/AbsDestFold NameImage
  # Создание образа. 
  # Параметры создания указываются в файле "Dockerfile", он может находится где угодно, при сборке указывается путь к нему, внутри него указывается исходный образ
docker build -t MyNewImage /PathToDockerfile
 
  # С удалением промежуточных образов
docker build --rm -t local/myImage ./[Dockerfile]
 
  # docker-compose (apt install docker-compose)
  # Создаем нужный файл yml, в директории и из этой же директории запускаем проект
docker-compose up [-d для фонового запуска]
 
 
  #  Тегирование и пуш в registry
docker tag local_image:latest REGISTRY_URL:RELEASE-BUILD_VERSION
docker push REGISTRY_URL:RELEASE-BUILD_VERSION
:!: Пример Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
FROM eclipse-temurin:17-jdk-alpine as builder
WORKDIR /opt/app
COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline
COPY ./src ./src
RUN ./mvnw clean install
 
FROM eclipse-temurin:17-jre-alpine
WORKDIR /opt/app
COPY --from=builder /opt/app/target/*.jar /opt/app/*.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/opt/app/*.jar"]

Собственные образы

В PATH передается расположение файлов для сборки, не стоит передавать большое т.к. все содержимое передается демону докера т.к. он занимается сборкой, можно делать файл «игнора».
Сам образ создается в репозитории, в опциях можно указывать параметры для репозитория.

  • -f - путь к файлу Dockerfile
  • -t - опции, можно указать имя создаваемого образа
:!: Пример: цикличный вывод из контейнеров в один общий файл

PS При указании пути, тильда не работает
read.sh:

#!/bin/bash
while true
do
        echo "--==" $(uname -a) "==--" >> /outdir/output.txt
        sleep 2
done

Dockerfile:

FROM debian
MAINTAINER im
RUN apt-get update && apt-get install procps -y
COPY read.sh /scrptdir/read.sh
CMD ["/scrpt/read.sh"]
  # Сборка
docker build -t imecho .
 
  # Запуск
docker run -dit --name contecho -v /home/dn/imread/outdir:/outdir imecho
:!: Докер файл с java приложением

Сборка java уже была

FROM openjdk:17
WORKDIR /app
COPY ./build/libs/*.jar ./my_app.jar
EXPOSE 8080/tcp
CMD ["java", "-Dspring.profiles.active=stage", "-Duser.timezone=GMT", "-jar", "my_app.jar"]

Сборку делаем здесь же

FROM gradle:7-jdk17 as build
WORKDIR /src
COPY . .
RUN --mount=type=cache,target=/home/gradle/.gradle . && \
    gradle wrapper && \
    ./gradlew compileJava && \
    ./gradlew test && \
    ./gradlew bootJar
 
FROM openjdk:17
WORKDIR /app
COPY ./build/libs/*.jar ./my_app.jar
EXPOSE 8080/tcp
CMD ["java", "-Dspring.profiles.active=stage", "-Duser.timezone=GMT", "-jar", "my_app.jar"]

Использование

Изменения сохраняются в контейнере, устанавливаемый софт например.
Создание с параметром -it (интерактивный с эмулятором) создает контейнер сразу с запущенным КИ, в противном случае без него и с-но останавливается сразу после запуска.

При повторном создании образа (через Dockerfile), образ пересоздается, типа следующая версия (latest), старый остается.

Docker-compose

Оркестрация несколькими контейнерами

docker-compose up -d 
docker-compose down
 
docker-compose -f filename -f filename2 up -d 
docker-compose -f filename -f filename2 down
:!: Info

Сеть создается автоматически, общая для всех контейнеров, контейнеры доступны друг другу по имени хоста
Параметры можно менять/задавать, можно подключаться к уже созданной сети, разве что для этого и имеет смысл специально указывать сеть в компоуз-файле

:!: Пример приложения и БД postgres

Приложение загружается с собственного registry, перед этим нужно выполнить «docker login»
Контейнеры объединяются в общую сеть
Создается постоянное хранилище, используемое базой данных

version: '3.7'
 
networks:
  my_app_net:
    name: my_net
 
volumes:
  pgdata:
    name: db_pgdata
    driver_opts:
      type: None
      device: /opt/pgdata
      o: bind
 
services:
  my_appication:
    image: registry.myapp.io/myapp/
    container_name: my_app
    restart: unless-stopped
    expose:
      - "8080"
    environment:
      - "DATABASE_URL=jdbc:postgresql://postgres:5432/<DATABASE_NAME>"
      - "DATABASE_USER=<DATABASE_USER_NAME>"
      - "DATABASE_PASSWORD=<DATABASE_USER_PASSWORD>"
    networks:
      - my_app_net
    depends_on:
      - postgres
 
  postgres:
    image: postgres:14
    command: ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]
    container_name: postgres
    restart: unless-stopped
    ports:
      - "5432:5432"
    environment:
      - "POSTGRES_PASSWORD=<DATABASE_POSTGRES_PASSWORD>"
    networks:
      - my_app_net
    volumes:
      - pgdata:/var/lib/postgresql/data
      - /opt/<APP_DIRECTORY>/postgres/postgresql.conf:/etc/postgresql/postgresql.conf
      - /opt/<APP_DIRECTORY>/postgres/pg_hba.conf:/etc/postgresql/pg_hba.conf
      - /opt/<APP_DIRECTORY>/postgres/initdb_stage:/docker-entrypoint-initdb.d
:!: Kafka и Zookeeper
version: '3.7'
 
services:
  zoo1:
    image: zookeeper
    hostname: zoo1
    container_name: zoo1
    ports:
      - "2181:2181"
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_SERVER_ID: 1
      ZOOKEEPER_SERVERS: zoo1:2888:3888
 
  kafka1:
    image: confluentinc/cp-kafka:latest
    hostname: kafka1
    container_name: kafka1
    ports:
      - "9092:9092"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: "zoo1:2181"
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
 
      KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka1:19092,EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
 
#      KAFKA_LOG4J_LOGGERS: "kafka.controller=INFO,kafka.producer.async.DefaultEventHandler=INFO,state.change.logger=INFO"
#      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
#      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
#      KAFKA_JMX_PORT: 9999
#      KAFKA_JMX_HOSTNAME: ${DOCKER_HOST_IP:-127.0.0.1}
#      KAFKA_AUTHORIZER_CLASS_NAME: kafka.security.authrizer.AclAuthorizer
#      KAFKA_ALLOW_EVERYONE_IF_NO_ACL_FOUND: "true"
    depends_on:
      - zoo1
  • KAFKA_ADVERTISED_LISTENERS - адреса для клиентов, в т.ч. для межброкерного взаимодействия
  • режим для межброкерного взаимодействия задается в «KAFKA_INTER_BROKER_LISTENER_NAME», но для этого в вышестоящем пар-ре должен быть прописан этот режим (internal/external)
:!: Еще пример с кафкой
version: "2"

services:
  zookeeper:
    image: docker.io/bitnami/zookeeper:3.9
    ports:
      - "2181:2181"
    volumes:
      - "zookeeper_data:/bitnami"
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes

  kafka0:
    image: docker.io/bitnami/kafka:3.4
    ports:
      - "9094:9094"
    volumes:
      - "kafka_data0:/bitnami"
    environment:
      - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
      - KAFKA_CFG_BROKER_ID=0
 
      - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094
      - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka0:9092,EXTERNAL://localhost:9094
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT

    depends_on:
      - zookeeper

  kafka1:
    image: docker.io/bitnami/kafka:3.4
    ports:
      - "9096:9096"
    volumes:
      - "kafka_data1:/bitnami"
    environment:
      - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
      - KAFKA_CFG_BROKER_ID=1
 
      - KAFKA_CFG_LISTENERS=PLAINTEXT://:9095,CONTROLLER://:9097,EXTERNAL://:9096
      - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka1:9095,EXTERNAL://localhost:9096
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT

    depends_on:
      - zookeeper

volumes:
  zookeeper_data:
    driver: local
  kafka_data0:
    driver: local
  kafka_data1:
    driver: local
version: "2"
 
services:
  zookeeper:
    image: docker.io/bitnami/zookeeper:3.9
    ports:
      - "2181:2181"
    volumes:
      - "zookeeper_data:/bitnami"
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
  kafka:
    image: docker.io/bitnami/kafka:3.4
    ports:
      - "9092:9092"
    volumes:
      - "kafka_data:/bitnami"
    environment:
      - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
    depends_on:
      - zookeeper
 
volumes:
  zookeeper_data:
    driver: local
  kafka_data:
    driver: local
:!:
 
linux/containers.txt · Последнее изменение: 2024/08/31 05:11 — admin