์ด ๊ธฐ์ฌ๋ ์์ ํ ์ค์ฉ์ ์ด๋ฉฐ ๋ด ์ฌํ ์ด์ผ๊ธฐ์ ์ ๋ ํฉ๋๋ค
์ค๋นํ๊ธฐ ์ ๋กํฐ์นํ๋ก๋ ์ฐ๋ฆฌ ๋ชจ๋๊ฐ ์ ์ฑ๊ฑฐ๋ฆฌ๊ณ ์๋ RDS(MS SQL)์ ๋ํด ์๋ํ์ ๋ํ ํ๋ ์ ํ ์ด์ (POC - Proof Of Concept), ์ฆ ์ผ๋ จ์ Powershell ์คํฌ๋ฆฝํธ๋ฅผ ๋ง๋ค์์ต๋๋ค. ํ๋ ์ ํ ์ด์ ์ด ๋๋ ํ ํญํ์ฐ๊ฐ ์น๋ ๊ธด ๋ฐ์๊ฐ ์ฌ๋ผ์ง๊ณ ๋์์๋ ๋ฐ์๋ก ๋ณํ์ ๋ ๊ทธ๋ค์ ๋์๊ฒ ๋งํ์ต๋๋ค. ์ด ๋ชจ๋ ๊ฒ์ด ์ข์ง๋ง ์ด๋ ์ ์ด์ ๋ก ๋ง ๋ชจ๋ Jenkins ๋ ธ์๊ฐ Linux์์ ์์ ํฉ๋๋ค!
์ด๊ฒ์ด ๊ฐ๋ฅํ๊ฐ? Windows์์ ๋ฐ๋ปํ ๋จํ DBA๋ฅผ ๊ฐ์ ธ์ Linux์์ Powershell์ ์ด๊ธฐ์ ๋ถ์ด์๊ฒ ์ต๋๊น? ์ด๊ฑด ์์ธํ์ง ์๋์?
๋๋ ์ด ์ด์ํ ๊ธฐ์ ์ ์กฐํฉ์ ๋ชฐ์
ํด์ผ ํ์ต๋๋ค. ๋ฌผ๋ก 30๊ฐ ์ด์์ ์คํฌ๋ฆฝํธ๊ฐ ๋ชจ๋ ์๋์ ๋ฉ์ท์ต๋๋ค. ๋๋๊ฒ๋ ๋๋ ๊ทผ๋ฌด์ผ ๊ธฐ์ค์ผ๋ก ํ๋ฃจ ๋ง์ ๋ชจ๋ ๊ฒ์ ๊ณ ์น ์ ์์์ต๋๋ค. ๋๋ ๋จ๊ฑฐ์ด ์ถ๊ตฌ์ ๊ธ์ ์ฐ๊ณ ์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด Powershell ์คํฌ๋ฆฝํธ๋ฅผ Windows์์ Linux๋ก ์ ์กํ ๋ ์ด๋ค ํจ์ ์ ์ง๋ฉดํ ์ ์์ต๋๊น?
sqlcmd ๋ Invoke-SqlCmd
๊ทธ๋ค ์ฌ์ด์ ์ฃผ์ ์ฐจ์ด์ ์ ์๊ธฐ์์ผ ๋๋ฆฌ๊ฒ ์ต๋๋ค. ์ข์ ์ค๋๋ ์ ํธ๋ฆฌํฐ SQLcmd ๋ํ ๊ฑฐ์ ๋์ผํ ๊ธฐ๋ฅ์ผ๋ก Linux์์๋ ์๋ํฉ๋๋ค. -Q๋ฅผ ์คํํ๊ธฐ ์ํด ์ฟผ๋ฆฌ๋ฅผ ์ ๋ฌํ๊ณ , ์ ๋ ฅ ํ์ผ์ -i๋ก, ์ถ๋ ฅ์ -o๋ก ์ ๋ฌํฉ๋๋ค. ๊ทธ๋ฌ๋ ํ์ผ ์ด๋ฆ์ ๋ฌผ๋ก ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํฉ๋๋ค. -i๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ํ์ผ ๋์ ๋ค์์ ์๋๋ค.
GO
EXIT
๋์ EXIT๊ฐ ์์ผ๋ฉด sqlcmd๋ ๊ณ์ํด์ ์ ๋ ฅ์ ๊ธฐ๋ค๋ฆฝ๋๋ค. EXIT ~ํ์ง ์์ ๊ฒ์ด๋ค GO, ๋ง์ง๋ง ๋ช ๋ น์ ์๋ํ์ง ์์ต๋๋ค. ์ถ๋ ฅ ํ์ผ์๋ ๋ชจ๋ ์ถ๋ ฅ, ์ ํ, ๋ฉ์์ง, ์ธ์ ๋ฑ์ด ํฌํจ๋ฉ๋๋ค.
Invoke-SqlCmd๋ ๊ฒฐ๊ณผ๋ฅผ DataSet, DataTables ๋๋ DataRows๋ก ์์ฑํฉ๋๋ค. ๋ฐ๋ผ์ ๋จ์ ์ ํ์ ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ต๋๋ค. SQLcmd, ์ถ๋ ฅ์ ๊ตฌ๋ฌธ ๋ถ์ํ ํ์๋ ๋ณต์กํ ๊ฒ์ ํ์ํ๋ ๊ฒ์ด ๊ฑฐ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค. ํธ์ถ-SqlCmd. ํ์ง๋ง ์ด ํ์๋ ๋ค์๊ณผ ๊ฐ์ ๋๋ด๋ ์์ต๋๋ค.
- ๋ค์์ ํตํด ๊ทธ๋ ์๊ฒ ํ์ผ์ ์ ์กํ๋ ๊ฒฝ์ฐ -์ ๋ ฅ ํ์ผ, ๊ทธ๋ฐ ๋ค์ EXIT ํ์ํ์ง ์์ผ๋ฉฐ ๋ํ ๊ตฌ๋ฌธ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
- -๊ฒฐ๊ณผ๋ฌผ ํ์ผ ์๋์, ๋ช ๋ น์ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ฒด๋ก ๋ฐํํฉ๋๋ค.
- ์๋ฒ๋ฅผ ์ง์ ํ๋ ๋ฐ๋ ๋ ๊ฐ์ง ๊ตฌ๋ฌธ์ด ์์ต๋๋ค. -ServerInstance -์ฌ์ฉ์ ์ด๋ฆ -์ํธ -๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ทธ๋ฆฌ๊ณ ํตํด -์ฐ๊ฒฐ ๋ฌธ์์ด. ์ด์ํ๊ฒ๋ ์ฒซ ๋ฒ์งธ ๊ฒฝ์ฐ์๋ 1433 ์ด์ธ์ ํฌํธ๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค.
- ํ
์คํธ ์ถ๋ ฅ์ PRINT๋ฅผ ์
๋ ฅํ๋ฉด ๊ฐ๋จํ "์กํ๊ฒ" ๋ฉ๋๋ค. SQLcmd~์ ์ํด ํธ์ถ-SqlCmd
๋ฌธ์ ์ด๋ค - ๊ทธ๋ฆฌ๊ณ ๊ฐ์ฅ ์ค์ํ ๊ฒ์ :
Linux์ ์ด cmdlet์ด ์์ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค!
๊ทธ๋ฆฌ๊ณ ์ด๊ฒ์ด ์ฃผ์ ๋ฌธ์ ์
๋๋ค. XNUMX์์๋ง ์ด cmdlet
๋ณ์ ๋์ฒด
sqlcmd์๋ -v๋ฅผ ์ฌ์ฉํ์ฌ ๋ณ์ ๋์ฒด๊ฐ ์์ต๋๋ค. ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
# $conn ัะพะดะตัะถะธั ะฝะฐัะฐะปะพ ะบะพะผะฐะฝะดั sqlcmd
$cmd = $conn + " -i D:appsSlaveJobsKillSpid.sql -o killspid.res
-v spid =`"" + $spid + "`" -v age =`"" + $age + "`""
Invoke-Expression $cmd
SQL ์คํฌ๋ฆฝํธ์์๋ ๋์ฒด๋ฅผ ์ฌ์ฉํฉ๋๋ค.
set @spid=$(spid)
set @age=$(age)
์ฌ๊ธฐ ์์ต๋๋ค. *nix์์๋ ๋ณ์ ๋์ฒด๊ฐ ์๋ํ์ง ์์ต๋๋ค. ๋ชจ์ -v ๋ฌด์๋์์ต๋๋ค. ์ ํธ์ถ-SqlCmd ๋ฌด์๋จ -๋ณ์. ๋ณ์ ์์ฒด๋ฅผ ์ง์ ํ๋ ๋งค๊ฐ๋ณ์๋ ๋ฌด์๋์ง๋ง ๋์ฒด ์์ฒด๋ ์๋ํฉ๋๋ค. Shell์ ๋ชจ๋ ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋๋ ๋ณ์์ ๊ธฐ๋ถ์ด ์ํ๊ณ ๋ณ์์ ์ ํ ์์กดํ์ง ์๊ธฐ๋ก ๊ฒฐ์ ํ์ผ๋ฉฐ SQL ์คํฌ๋ฆฝํธ๊ฐ ์งง๊ธฐ ๋๋ฌธ์ ๋ฌด๋กํ๊ณ ์์์ ์ผ๋ก ํ๋ํ์ต๋๋ค.
# prepend the parameters
"declare @age int, @spid int" | Add-Content "q.sql"
"set @spid=" + $spid | Add-Content "q.sql"
"set @age=" + $age | Add-Content "q.sql"
foreach ($line in Get-Content "Sqlserver/Automation/KillSpid.sql") {
$line | Add-Content "q.sql"
}
$cmd = "/opt/mssql-tools/bin/" + $conn + " -i q.sql -o res.log"
์์๋ค์ํผ ์ด๊ฒ์ ์ด๋ฏธ Unix ๋ฒ์ ์ ํ ์คํธ์ ๋๋ค.
ํ์ผ ์ ๋ก๋
Windows ๋ฒ์ ์์๋ ๋ชจ๋ ์์ ์ ๊ฐ์ฌ๊ฐ ์๋ฐ๋์์ต๋๋ค. sqlcmd๋ฅผ ์คํํ๊ณ ์ถ๋ ฅ ํ์ผ์์ ์ผ์ข ์ ๋จ์ฉ์ ๋ฐ์๊ณ ์ด ํ์ผ์ ๊ฐ์ฌ ํ๋ ์ดํธ์ ์ฒจ๋ถํ์ต๋๋ค. ๋คํ์ค๋ฝ๊ฒ๋ SQL ์๋ฒ๋ Jenkins์ ๋์ผํ ์๋ฒ์์ ์๋ํ์ผ๋ฉฐ ๋ค์๊ณผ ๊ฐ์ด ์ํ๋์์ต๋๋ค.
CREATE procedure AuditUpload
@id int, @filename varchar(256)
as
set nocount on
declare @sql varchar(max)
CREATE TABLE #multi (filer NVARCHAR(MAX))
set @sql='BULK INSERT #multi FROM '''+@filename
+''' WITH (ROWTERMINATOR = '' '',CODEPAGE = ''ACP'')'
exec (@sql)
select @sql=filer from #multi
update JenkinsAudit set multiliner=@sql where ID=@id
return
๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ BCP ํ์ผ ์ ์ฒด๋ฅผ ์ผ์ผ ๊ฐ์ฌ ํ ์ด๋ธ์ nvarchar(max) ํ๋์ ๋ฐ์ด ๋ฃ์ต๋๋ค. ๋ฌผ๋ก , ์ด ์ ์ฒด ์์คํ ์ ๋ฌด๋์ก์ต๋๋ค. SQL ์๋ฒ ๋์ RDS๋ฅผ ์ป์๊ณ ํ์ผ์ ๋ํ ๋ฐฐํ์ ์ ๊ธ์ ์๋ํ๊ธฐ ๋๋ฌธ์ UNC๋ฅผ ํตํด BULK INSERT๊ฐ ์ ํ ์๋ํ์ง ์๊ณ RDS๋ฅผ ์ฌ์ฉํ๋ฉด ์ผ๋ฐ์ ์ผ๋ก ํ๋ฉธ๋ฉ๋๋ค. ๋งจ ์ฒ์. ๊ทธ๋์ ์ ๋ ์์คํ ์ค๊ณ๋ฅผ ๋ณ๊ฒฝํ์ฌ ๊ฐ์ฌ๋ฅผ ํ ์ค์ฉ ์ ์ฅํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
CREATE TABLE AuditOut (
ID int NULL,
TextLine nvarchar(max) NULL,
n int IDENTITY(1,1) PRIMARY KEY
)
๊ทธ๋ฆฌ๊ณ ์ด ํ์ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ์ธ์.
function WriteAudit([string]$Filename, [string]$ConnStr,
[string]$Tabname, [string]$Jobname)
{
# get $lastid of the last execution -- ะฟัะพัะบะธะฟะฐะฝะพ ะดะปั ััะฐััะธ
#create grid and populate it with data from file
$audit = Get-Content $Filename
$DT = new-object Data.DataTable
$COL1 = new-object Data.DataColumn;
$COL1.ColumnName = "ID";
$COL1.DataType = [System.Type]::GetType("System.Int32")
$COL2 = new-object Data.DataColumn;
$COL2.ColumnName = "TextLine";
$COL2.DataType = [System.Type]::GetType("System.String")
$DT.Columns.Add($COL1)
$DT.Columns.Add($COL2)
foreach ($line in $audit)
{
$DR = $dt.NewRow()
$DR.Item("ID") = $lastid
$DR.Item("TextLine") = $line
$DT.Rows.Add($DR)
}
# write it to table
$conn=new-object System.Data.SqlClient.SQLConnection
$conn.ConnectionString = $ConnStr
$conn.Open()
$bulkCopy = new-object ("Data.SqlClient.SqlBulkCopy") $ConnStr
$bulkCopy.DestinationTableName = $Tabname
$bulkCopy.BatchSize = 50000
$bulkCopy.BulkCopyTimeout = 0
$bulkCopy.WriteToServer($DT)
$conn.Close()
}
์ฝํ ์ธ ๋ฅผ ์ ํํ๋ ค๋ฉด ID๋ณ๋ก ์ ํํด์ผ ํ๋ฉฐ, n(ID) ์์ผ๋ก ์ ํํด์ผ ํฉ๋๋ค.
๋ค์ ๊ธฐ์ฌ์์๋ ์ด ๋ชจ๋ ๊ฒ์ด Jenkins์ ์ด๋ป๊ฒ ์ํธ ์์ฉํ๋์ง ์์ธํ ์ค๋ช
ํ๊ฒ ์ต๋๋ค.
์ถ์ฒ : habr.com