Linux Container SSH Bağlantısı

Bu yazıda özetle bir docker konteynerden diğerine ssh (container to container ssh) ile bağlanma örneği yapacağız.

İş hayatında sık sık bir uzak linux sunucuya bağlanıyoruz. Bu bağlantı için SSH protokolünü kullanıyoruz. Teknik olarak SSH (Secure Shell), bir ağ üzerinden iki bilgisayar arasında güvenli bir şekilde veri alışverişi ve uzaktan oturum açma imkanı sağlayan bir kriptografik protokoldür. Peki Docker ortamında demo, POC, eğitim vb. amaçlarla konteynerler arasında SSH bağlantısı yapmak gerekirse bunu nasıl yapacağız. Normal bir linux işletim sistemi üzerinde ssh sunucusu kurmak ayarlamak ve ona bağlanmak kolay ve bununla ilgili bir çok doküman veya makale var. Benim ihtiyacım oldu ve pek bir kaynak bulamadım. Bu ihtiyacımı çözdüm ve benim gibi insanlar için nasıl çözdüğümü bu yazıda paylaşacağım.

İki tane konteyner olacak. İlki jenkins, ikincisi bir rockylinux konteyner (prod_server).

Kendimize çalışma klasörü yaratalım ve içinde docker-compose.yaml dosyasını oluşturalım.

(base) [train@localhost ~]$ mkdir blog_ssh
(base) [train@localhost ~]$ cd blog_ssh/
(base) [train@localhost blog_ssh]$ touch docker-compose.yaml

compose dosyası

version: '3.7'
services:
  jenkins:
    restart: always
    build: ./jenkins
    image: jenkins_server
    container_name: jenkins
    ports:
        - "8080:8080"
        - "50000:50000"
    volumes:
      - jenkins_home:/var/jenkins_home
      - "/var/run/docker.sock:/var/run/docker.sock"
  prod_server:
    build: ./prod
    image: prod_server
    container_name: prod_server
    hostname: prod_server
    privileged: true
    ports:
        - "8000:8000"
        - "2222:22"
    security_opt:
      - seccomp:unconfined
    tmpfs:
      - /run
      - /run/lock
    volumes:
        - ./prod/home/.ssh:/home/prod_user/.ssh
        - /sys/fs/cgroup:/sys/fs/cgroup:ro
volumes:
  jenkins_home:

Yukarıdaki prod_server servisi ayarlarından önemli olanları açıklayalım:

  • build: ./prod

    • Bu ayar, prod_server imajını oluşturmak için kullanılacak Dockerfile’ın bulunduğu dizini belirtir. Bu durumda, Dockerfile, prod adlı bir dizin içinde yer almaktadır.
  • privileged: true

    • Bu ayar, konteynere ana bilgisayar sisteminde normalde kısıtlanmış işlemleri gerçekleştirme yetkisi verir. Bu, örneğin Docker içinde Docker çalıştırmak veya bazı düşük seviyeli sistem ayarlarını değiştirmek gibi durumlarda gerekli olabilir. Ancak, güvenlik risklerini artırabileceğinden dikkatli kullanılmalıdır.
  • security_opt:

    • seccomp:unconfined: Konteyner üzerindeki Seccomp güvenlik profilini devre dışı bırakır. Bu, bazı özel durumlarda gerekli olabilir, ancak genellikle güvenlik risklerini artırabileceğinden önerilmez.
  • tmpfs:

    • /run ve /run/lock: Bu dizinleri geçici bir dosya sistemi (tmpfs) olarak bağlar. Bu, konteynerin performansını artırabilir, ancak konteyner yeniden başlatıldığında bu dizinlerdeki veriler kaybolur.
  • volumes:

    • ./prod/home/.ssh:/home/prod_user/.ssh: Ana bilgisayardaki ./prod/home/.ssh dizinini, konteyner içindeki /home/prod_user/.ssh dizinine bağlar. Bu, SSH anahtarları gibi önemli dosyaları konteyner içinde kalıcı hale getirmek için kullanılır.
    • /sys/fs/cgroup:/sys/fs/cgroup:ro: Ana bilgisayardaki cgroup dosya sistemini, konteyner içinde salt okunur olarak bağlar. Bu, konteynerin kaynak kullanımını kontrol etmek için gereklidir.

Özgün Dockerfile’lar.

  • jenkins
mkdir jenkins

cat<<EOF | tee jenkins/Dockerfile
FROM jenkins/jenkins:lts-jdk17

USER root

# Install ansible
RUN apt update && \
apt -y install python3-distutils && \
apt -y install python3-apt && \
apt -y install python3 && \
apt -y install iputils-ping netcat-traditional

RUN apt-get install -y python3-pip

RUN pip install -U ansible --break-system-packages

RUN apt-get -y install rsync

USER jenkins
EOF
  • FROM jenkins/jenkins:lts-jdk17

    • Bu satır, Docker imajının temelini belirler. jenkins/jenkins:lts-jdk17 imajını kullanarak, Jenkins’in uzun süreli destek (LTS) sürümünü ve OpenJDK 17’yi içeren bir temel imaj oluşturulur.
  • USER root

    • Docker imajının içindeki kullanıcıyı root kullanıcısına geçirir. Bu, sonraki adımlarda yönetici ayrıcalıkları gerektiren işlemleri gerçekleştirmek için gereklidir.
  • RUN apt update && \ apt -y install python3-distutils && \ apt -y install python3-apt && \ apt -y install python3 && \ apt -y install iputils-ping netcat-traditional

    • Bu blok, birkaç paketin kurulumunu gerçekleştirir:
      • apt update: Paket listelerini günceller.
      • apt -y install ...: Aşağıdaki paketleri yükler:
        • python3-distutils: Python 3 için dağıtım yardımcı programları sağlar.
        • python3-apt: Python 3 için APT (Advanced Package Tool) kitaplığını sağlar.
        • python3: Python 3 yorumlayıcısını yükler.
        • iputils-ping: ping komutunu sağlar, ağ bağlantısını test etmek için kullanılır.
        • netcat-traditional: nc (netcat) komutunu sağlar, TCP/UDP bağlantıları açmak ve veri göndermek/almak için kullanılır.
  • RUN apt-get install -y python3-pip

    • Python 3 için pip paket yöneticisini yükler. pip, Python paketlerini kurmak ve yönetmek için kullanılır.
  • RUN pip install -U ansible --break-system-packages

    • Ansible’ı yükler veya günceller. --break-system-packages seçeneği, Ansible’ın bağımlılıklarını yüklerken sistem paketleriyle çakışmaları çözmek için kullanılır.
  • RUN apt-get -y install rsync

    • rsync komutunu yükler. rsync, dosyaları ve dizinleri uzak veya yerel sistemler arasında verimli bir şekilde senkronize etmek için kullanılır.
  • USER jenkins

    • Kullanıcıyı tekrar jenkins kullanıcısına geçirir. Bu, Jenkins işlemlerinin jenkins kullanıcısı altında çalışmasını sağlar, güvenlik açısından iyi bir uygulamadır.
  • prod_server
mkdir prod

cat<<EOF |tee prod/Dockerfile
FROM rockylinux:8.6

ENV container docker

RUN yum -y update && yum clean all

RUN yum -y install openssh-server  python3 sudo passwd  systemd

RUN adduser -m prod_user && \
    echo "Ankara06" | passwd prod_user --stdin && \
    usermod -aG wheel prod_user && \
    mkdir /home/prod_user/.ssh && \
    chown prod_user:prod_user -R  /home/prod_user/ && \
    chmod 700 /home/prod_user/.ssh

RUN     echo "%wheel         ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers

RUN echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config

RUN systemctl enable sshd.service

RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;

COPY init_script.sh /etc/init.d/

VOLUME [ "/sys/fs/cgroup" ]

CMD ["/usr/sbin/init"]
EOF
  • FROM rockylinux:8.6:

    • Bu Dockerfile, Rocky Linux 8.6 sürümünü temel alarak bir imaj oluşturur. Temel imaj, işletim sistemi ve temel araçları içerir.
  • ENV container docker:

    • container adında bir ortam değişkeni oluşturur ve değerini docker olarak ayarlar. Bu değişken, konteynerin bir Docker konteyneri olduğunu belirtmek için kullanılabilir.
  • RUN yum -y update && yum clean all:

    • Sistem paketlerini günceller (yum -y update) ve ardından eski paketleri ve önbellekleri temizler (yum clean all).
  • RUN yum -y install openssh-server python3 sudo passwd systemd:

    • Gerekli paketleri yükler:
      • openssh-server: SSH sunucusunu kurar, böylece konteyner uzaktan SSH bağlantılarına izin verir.
      • python3: Python 3 yorumlayıcısını kurar.
      • sudo: sudo komutunu sağlar, kullanıcıların belirli komutları yönetici ayrıcalıklarıyla çalıştırmasına izin verir.
      • passwd: Kullanıcı parolalarını yönetmek için passwd komutunu sağlar.
      • systemd: Sistem ve servis yönetimi için systemd’yi kurar.
  • RUN adduser -m prod_user && \ echo "Ankara06" | passwd prod_user --stdin && \ usermod -aG wheel prod_user && \ mkdir /home/prod_user/.ssh && \ chown prod_user:prod_user -R /home/prod_user/ && \ chmod 700 /home/prod_user/.ssh:  

    • prod_user adında yeni bir kullanıcı oluşturur ve ona bir ev dizini (-m) atar.
    • Kullanıcının parolasını “Ankara06” olarak ayarlar.
    • Kullanıcıyı wheel grubuna ekler, böylece sudo kullanarak yönetici ayrıcalıklarıyla komutlar çalıştırabilir.
    • /home/prod_user/.ssh dizinini oluşturur ve sahipliğini prod_user kullanıcısına verir.
    • /home/prod_user/ dizininin sahipliğini ve izinlerini ayarlar, böylece sadece prod_user erişebilir.
    • /home/prod_user/.ssh dizininin izinlerini ayarlar, böylece sadece sahibi okuma, yazma ve yürütme yapabilir.
  • RUN echo "%wheel ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers:

    • wheel grubundaki kullanıcıların parola sorulmadan sudo kullanarak herhangi bir komutu çalıştırmasına izin verir. Bu, otomatikleştirilmiş görevler için kullanışlı olabilir, ancak güvenlik risklerini artırabilir, bu nedenle dikkatli kullanılmalıdır.
  • RUN echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config:

    • SSH sunucusunun yapılandırma dosyasına PasswordAuthentication yes satırını ekler. Bu, SSH bağlantılarında parola tabanlı kimlik doğrulamayı etkinleştirir.
  • RUN systemctl enable sshd.service:

    • SSH sunucusunu sistem başlangıcında otomatik olarak başlatacak şekilde ayarlar.
  • RUN (cd /lib/systemd/system/sysi ... sytemd çalışması için gerekli dosyaları konteyner içinden kaldırır.
  • COPY init_script.sh /etc/init.d/:

    • init_script.sh adlı bir dosyayı ana bilgisayardan konteyner içindeki /etc/init.d/ dizinine kopyalar. Bu betik, muhtemelen konteyner başlatıldığında bazı ek başlatma görevlerini gerçekleştirir.
  • VOLUME [ "/sys/fs/cgroup" ]:

    • Konteyner içindeki /sys/fs/cgroup dizinini bir volume olarak tanımlar. Bu, ana bilgisayarın cgroup dosya sistemine erişim sağlar, bu da konteynerin kaynak kullanımını kontrol etmek için önemlidir.
  • CMD ["/usr/sbin/init"]:

    • Konteyner başlatıldığında çalıştırılacak varsayılan komutu belirtir. /usr/sbin/init, systemd’yi başlatır ve sistemin önyükleme işlemini tamamlar.

prod_server ayağa kalkınca sshd servisini çalıştıracak ve bir dosyayı silecek script’i oluşturalım. Bunu Dockerfile içinde de görebiliyorsunuz.

  • init_script.sh
cat<<EOF | tee init_script.sh
#!/bin/bash

systemctl start sshd 
sleep 3 
rm -f /run/nologin

# Execute the original CMD
exec "$@"
EOF

Bu script imaj içine gömülür ve konteyner ayağa kaltıktan sonra /etc/init.d/init_script.sh olarak hazır olur. Konteyner çalışırken bu script çalışında sshd servisi çalışacaktır.

Nihai olarak dosya ve dizin yapısını bir görelim.

tree
.
├── docker-compose.yaml
├── init_script.sh
├── jenkins
│   └── Dockerfile
└── prod
    ├── Dockerfile
    └── init_script.sh

3 directories, 5 files

Windows dosya sisteminde kaydedildikten sonra sh dosyalarında bazı arızalar olabiliyor. Onları düzeltelim her ihtimale karşı ve çalıştırılabilir (executable) yapalım.

chmod +x  prod/init_script.sh

sed -i 's/\r$//' prod/init_script.sh

Ortamı ayağa kaldırma

docker-compose up --build -d

prod_server volume için şuanki kullanıcımıza (train) yetki verelim.

sudo chown train:train -R prod/home/

prod_server sshd servisini çalıştırma. Bunu konteyner içine gönderdiğimiz init_script.sh ile yapacağız.

docker exec -it prod_server /etc/init.d/init_script.sh

sshd çalışmış mı kontrol edelim.

docker exec -it prod_server systemctl status sshd


● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; disabled; vendor preset: enabled)
   Active: active (running) since Thu 2024-08-22 03:45:02 UTC; 54s ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 88 (sshd)
    Tasks: 1 (limit: 24102)
   Memory: 1.7M
   CGroup: /docker/ed3ff6abc5eeae345c731e8a8c308e759f79c66167a743af859afbeefa324abe/system.slice/sshd.s>
           └─88 /usr/sbin/sshd -D -oCiphers=aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256>

Aug 22 03:45:02 prod_server systemd[1]: Starting OpenSSH server daemon...
Aug 22 03:45:02 prod_server sshd[88]: Server listening on 0.0.0.0 port 22.
Aug 22 03:45:02 prod_server sshd[88]: Server listening on :: port 22.
Aug 22 03:45:02 prod_server systemd[1]: Started OpenSSH server daemon

Evet şuan çalışıyor.

jenkins sunucusundan ssh ile prod server’a bağlanmayı deneyelim. Password sorulduğu yerde kutsal password Ankara06 giriyoruz.

docker exec -it jenkins bash

jenkins@515eab58379e:/$ ssh prod_user@prod_server
The authenticity of host 'prod_server (172.18.0.3)' can't be established.
ED25519 key fingerprint is SHA256:InXqKoqOxd61f5JUnKEk8R64aqBm3/MwnZU9VwY0eco.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'prod_server' (ED25519) to the list of known hosts.
prod_user@prod_server's password: Ankara06

[prod_user@prod_server ~]$

[prod_user@prod_server ~]$ ifadesi bizim ssh ile jenkins’ten prod_server’a bağlandığımız anlamına geliyor.

Hayırlı uğurlu olsun.

Kullanılan tüm kodlar burada. Kendinizi bu konularda geliştirmek ve teknik olarak güçlendirmek için VBO Data Engineering Bootcamp‘e katılabilirsiniz.

Bir sonraki yazıya kadar hoşçakalın.

Kaynaklar

Kapak Görseli: Photo by Nikolett Emmert on Unsplash

Yazar Hakkında
Toplam 180 yazı
Erkan ŞİRİN
Erkan ŞİRİN
10 yılı aşkın süredir yurtiçi ve yurtdışında sektörde büyük veri mühendisliği, platform yönetimi ve makine öğrenmesi ile ilgili çalışmalar yürütmekte ve aynı zamanda birçok kurum ve şirkete danışmanlık ve eğitimler vermektedir. Çalışma alanları: Data ve MLOps platformları, gerçek zamanlı veri işleme, değişen veriyi yakalama (CDC) ve Lakehouse.
Yorumlar (Yorum yapılmamış)

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

×

Bir Şeyler Ara